Hacker Newsnew | past | comments | ask | show | jobs | submit | xxs's commentslogin

ref counting is expensive in multi-threaded applications. Overall it would have worse performance. When it comes to predictability: deallocating a linked list (for instance) would have to deallocate all of the elements. Dealing with reference cycles is also not simple, either.

Linked-list freeing need not all happen in one go. There can be a queue of free-but-not-zeroed, push RC=0 stuff there instead of recurring on referents, anyone doing memory allocation work can pop a few items off that queue and decrement the counts of their referents, etc.

That loses timeliness, adds problem of queue management.

A weird trick I stumbled across years ago is to not strictly pop from the head of the stack/queue -- instead choose randomly from the last N elements of push end of the stack. This seemed to blunt the sort of growth that you get from "visiting wrong". I never did figure out the theory of why this worked.


Honestly some (container) objects makes me think that they should be "parent obj management only"

For GC enabled languages swap is universally bad. Some gc-pauses are indistinguishable from a system crash. It's a side effect on not having tightly specified memory limits.

I'd rather have applications be oom_killed than having them swap out, the former is rather obvious and demands action.


If you want you application to stay in memory, then make it explicitly with mlock()/mlockall().

Disabling swap will just moves pressere elsewhere: to code pages. And evicted code page is no better: full stall while kernel loads that page from disk.


FYI: This `delamon` account seems to be meat proxying us. Just relaying garbage AI answers without understanding his own words. Doubt he's ever used mlock himself for anything.

His reply below was presumably killed by mods for doing this: https://news.ycombinator.com/item?id=49970841


I'm not. If you think that I said something not correct, do correct me. We're all learning.

I see that you've rewritten your AI generated reply there. So when have you used mlock in production for Go services, the way you're advising others to do? What were the circumstances?

I did not rewrite anything.

Yes, I was and still running go and zig binaries with mlockall. Apps have large in-application caches and also perform large streaming reads of datasets bigger than available RAM. If it happens that several streaming reads running at same time, they push memory pressure hard enough, so kernel swaps out cold parts of in-app caches. That later leads to elevated latencies => mlockall to avoid that.


I think discussing it in a vacuum is pointless, it should depend on how much memory you have. You can have a swap on, but with a low `vm.swappiness` number.

The point is that disabling swap does not prevent page eviction. Instead of swap, this discussion should be about the page cache.

Surely as long as it is all in memory these pauses are not going to be that significant, details like that should be left for the language devs to optimize.

You can tell an average Golang user to use mutexes, you shouldn't be telling them to lock memory manually.


vm.swappiness doesn’t work the way most people assume it does. and it is ignored under heavy memory pressure.

Maybe, but it still there and probably has a different value between distros as well. Default value is 60, what is that good for exactly?

If you're in a position where you still want swap to be there, but only used in extreme situations, then you should set it yourself. Otherwise disable swap or switch a language.


What do you think this value of 60 means? Also, as I said, in extreme situations, when the system is right before invoking the OOM killer, swap is used regardless of `vm.swappiness` setting.

> What do you think this value of 60 means?

Some arbitrary number.

https://docs.kernel.org/admin-guide/sysctl/vm.html#swappines...

> At 0, the kernel will not initiate swap until the amount of free and file-backed pages is less than the high watermark in a zone.

I don't see a reason why the default shouldn't be 0 then on modern systems.


Disabling swap disables loading a process' binary to memory? Or do you mean that evicted code pages will need to get loaded from disk every time.

There are two types of pages: anonymous and mapped from files. The code pages are mapped from a binary; they are not very special.

Under memory pressure, the kernel evicts less popular pages from memory. If a page has been mapped from a file, it is dropped (if dirty, then it is written out first). If it is needed later, the kernel can read it back from the file. If a page is anonymous (read: heap page), then there is no backing file and the kernel copies it to swap before dropping it. This is swapping.

So, what happens if you disable swap and the kernel is low on memory? What can it evict? Anonymous pages cannot be evicted: there is no swap to put a copy in. The only choice the kernel has is to evict pages that are mapped from files. Those include pages mapped from the executable. You don't eliminate stalls by disabling swap, you just move them elsewhere: the kernel will page out code and your app gets paused whenever the execution flow hits such a page.


Thanks for the clarification, learning everyday.

I haven't had to analyze the performance of no-swap processes before. My assumption is that code is hot enough to avoid eviction and that evicted code pages are rather the exception. To strong-man the argument, I can imagine long running complex (bloated) services could have parts that are not touched unless a specific request comes in.


>So, what happens if you disable swap and the kernel is low on memory? What can it evict?

Your userspace early OOM killer triggers and lets you know you're trying to run more than will fit in memory so you don't do it again. (In my experience, the kernel OOM killer can't be trusted to kill processes soon enough.)


You are missing that the file LRU is not only the code pages or memory mapped files but all file data. The active code pages are specifically excluded from being discarded during the reclaim process.

Perhaps I wasn't clear, but I did say that all file pages are treated equally. I would assume that page with PC is excluded from reclamation process, but other code pages are valid targets.

All code pages in the active file LRU are excluded from the reclaim.

All recently referenced code pages in the active LRU are excluded from reclaim.

Code pages are paged in on demand: for any sufficiently large binary just some code pages will be mapped right after start. Given enough memory pressure, the active LRU will be shrunk often enough to push code pages out of the active LRU and then they are eventually evicted.

I'm not aware how it works in modern MGLRU, but I would assume similar ovservable behevior holds.


Active code pages with the "Accessed" bit set are specifically excluded from being moved to inactive LRU when active LRU is being shrunk. Instead, they are moved to the head of the active LRU. All other pages are moved from active LRU to the inactive LRU unconditionally, even if they have the "Accessed" bit set. So, no, the active code pages are not going to be eventually evicted.

I think we are saying the same thing. Active code pages are not evicted; non-active code pages (that is, pages that had not been accessed since last time of active LRU shrinking) may be evicted.

I wish this is true but evidence is against you. Just try testing memory pressure on a no swap system. You will see that the system grinds to a half for a few minutes before you even get to an OOM event.

Could you clarify what exactly is "not true"? Also, could you explain what exactly your evidence proves? What do you think happens when the system becomes unresponsive under memory pressure, and why?

> The active code pages are specifically excluded from being discarded during the reclaim process.

This is not true, or the system wouldn't grind to a halt due to having to reload code pages (even those that are recently in use) from disk over and over.

For example, key presses and output streaming in SSH become unresponsive. The code pages for handling key presses and output streaming are obviously in use — I just used them!


I'll try again. Why do you think that unresponsiveness is caused by code pages being discarded? Do you have evidence for this? Have you considered that there are other mechanisms that cause programs to become unresponsive under memory pressure?

It's the explanation that I've read when scouring forums for reasons why it happens. I'd love to hear alternative explanations and how to measure/verify them. But the measurement tools also become unresponsive so I can't check anything.

But frankly, as a user I don't really care what the real technical reason is. I just don't think the system should become unresponsive for minutes on end during memory pressure. Just OOM-kill earlier, when it's supposed to.


Under memory pressure the system will free the ram used for code pages because it can always load them back from the executable on disk. It’s the same virtual memory mechanism as swap but without needing dedicated swap space. The op is saying disabling swap doesn’t prevent long pauses during memory pressure, because the system just swaps code out instead of dynamically allocated memory.

There are good sibling replies answering your question, but to give a specific example: if your application writes something but then doesn't need it anymore. Since we're talking about go, perhaps a data structure you need also holds a reference to data you don't need.

When the kernel needs memory, it goes hunting for a page it can discard. But since that's transparent, the kernel can only discard a page if it knows it can get it back (after all, it's still got valid data on it, and maybe you'll try access it again later).

If there's swap, a page full of stale/unneeded data can be written out to swap. But if there's no swap, your page of "dangling data that you'll never use, but is still valid & referenced" can't be discarded; the kernel doesn't know you won't want it later, and it can't recreate the page if it throws it away.

So like sibling said, at that point it has to find other pages it can evict from memory, ones that _do_ have somewhere persistent they can be written out to. Pages loaded from binaries on disk satisfy that, so those will get dropped instead.


For JIT languages most of the code is dynamically generated, not available to be loaded back from the disk. Morealso, the allocations do happen at large chucks where the oom_killer also happens, so it's significantly less of an issue.

That doesn't necessarily improve matters. Now any code that gets JIT'd is also going to be permanently pinned in memory too, no matter whether it'll get used again, if you don't have swap.

Under normal conditions the code gets jitted after some use... and the VM is free to deoptimize it when it reaches its max allowed generated cache.

The only code in danger is the one from libraries (e.g. zlib)


While I've seen systems grinding to a halt due to evicting code pages, the idea that disabling swap distributes load between code pages and data pages makes no sense to me. Data pages are also disk backed, so they could also be evicted at any time. Why would data pages be written to swap if they came fron the disk in the first place?

So that only leaves anonymous data pages, i.e., regular data in memory, that could be swapped. Ok but you're not easing the load on code pages, those still get evicted during memory pressure whether you have swap or not.


The assumption that data pages can always be easily discarded is incorrect. Dirty data pages can't be discarded until they are written back. Recently accessed data pages are also not discarded until all inactive data and code pages are discarded.

Please read the article. The issue was caused by swapped out metadata being read in a critical section, not typical heap traversal shenanigans.

This is not exclusive to GC, any program that reads a rarely accessed piece of memory is vulnerable to this.


Run your process in a cgroup that's set to disallow swap, then. The rest of your system benefits from having swap. This was an easy and safe thing that required minimal convincing to roll out to production at my company.

>to en-US would see the American site even if they live somewhere else.

Instead we have google that would serve the pages based off the local ip (and switch any time possible) which is a "horrific" experience travelling through Europe. You get a different language every day. Totally ignoring the accept-language header.

It's even funnier as the roaming would result in having the host mobile network IP regardless where a person resides - still ignoring the lang header, of course.


...oddly enough:

  - it notifies if your kids (or spouse) have left the door open.
  - you can use as a tool to check if the power company (or the road maintenance one!) has managed to reconnect the power back (or cut it, as in literally)

  - Other than that not so much.

> Windows users should use 7-Zip

Please no - no native zstd support. NanaZip is the better option (it's a different build of 7-zip) and it's available at windows store.

> Better compression format, unpacks more kinds of archives

winrar has supported zstd for 5 years[0]

In short - Everyone should be using zstd, and 7-zip does not support it.

[0]: https://www.win-rar.com/singlenewsview.html?&L=0&tx_ttnews%5...


Yeah, zstd is awesome. I built a webapp that uses it via wasm and the decompression speed is incredible, so much so that I store everything in zstd and decompress it on the app load. My wasm binary also does advanced search and tag insertion and stuff in addition to zstd but it's only 38kb. I wish zstd was supported natively by web browsers. The 8kb implementation of zstd is only half as slow as wasm, so even that is still viable.


Lzma. I did a simple test, same payload repeated with a gap. Lzma ruled it.

|gap |gzip |bz2 |lzma | |---------|----------|-----|--------| |0 |2.7% |18.9%|*0.9%*| |8 KB |2.4% |17.8%|0.9% | |*40 KB*|*94.4%* |17.7%|0.4% | |1 MB |*104.3%*|19.7%|*0.9%*|


HN doesn’t support Markdown tables. You can prepend two spaces to show it in monospace though.

I don’t see zstd in your comparison?


dont know the point of the table, but here it is:

  |gap      |gzip      |bz2  |lzma    | 
  |---------|----------|-----|--------|
  |0        |2.7%      |18.9%|  *0.9%*| 
  |8 KB     |2.4%      |17.8%|   0.9% |
  |*40 KB*  |*94.4%*   |17.7%|   0.4% |
  |1 MB     |*104.3%*  |19.7%|  *0.9%*|


seconding others' request to try with zstd! I'd be very curious what something like zstd -14 would give you

Good point. Looks like it’s related to window size (incl for lzma btw). Lzma stays 0.9 and goes to 88.5 post 8.8M gap. Zstd -14 is close to lzma up to 4.4M where it jumps to 91.5. 14L seems to be the best overall for this scenario staying at 1.9.

zstd is a good default for e.g. filesystem compression, but if you're making an archive file, presumably you're looking for higher compression and LZMA would be a better fit.


> Everyone should be using zstd

Why?


It's just the best general purpose compression algorithm, in terms of compression ratio to CPU used, for the vast majority of use cases


I'm not that fussed about CPU use.

https://github.com/mcmilk/7-Zip-zstd

By these charts, if I only need 5-10 megabytes per second of compression on a single core, LZMA2 wins significantly on ratio, and still decompresses at well over 100. If I'm doing a backup, or sending/receiving over my internet connection (which only has 2MB/s of upload), LZMA2 easily wins. If I need speed then zstd wins.


It's just this good.

On a more realistic note: few years back, I've added zstd compression to our log subsystem (hand written direct buffers, native code, in-process, java). For the same CPU utilization if provides twice dense compression compared to regular [-6] gzip (the topic in the title). Zstd is =much= faster on decompression as well, and it this case - unparalleledly better as it uses twice less disk.

zstd is 'silicon valley' (the tv show) - life imitates fiction, except entirely open source


>> Windows users should use 7-Zip

7z is now built into W11 right click so that or zip is what will be used by default anyway.


Last I checked windows handles compressed files in 4 byte or 4kb or something chunks and is incredibly slow to compress or decompress a lot of files.

What prevents passkey being used alongside password (+ email 2fa)?


Email 2fa otoh is the worst UX I have experienced. I curse every time Claude sends me a magic link. Absolutely hate them.


Not sure this is what I meant. Password is still stored, along will all the keypass stuff. If you have the option to login with the keypass... or the password - possibly sending you a link (or code) to the email, in case the device/browser has not been seen, yet.


You don't like not having to worry that they don't store your creds so they can't lose it?


The creds they store hold no value. These creds only give access to their system anyway. They store the email address either way so the situation is no better but less convenient.


They hold no value precisely because they don't store them and send you a magic link! If they stored a recycled password or its hash, then it would be valuable.


Yes but I use separate passwords and webauthn is per domain as well.


Slavery is a weird one. It has been there for longer than any written history exists. In ancient times (Greece, Rome), slaves didn't have rights at all. A horrific injustice but it'd be not be a theft. Then you get the serfdom in the middle ages. Up to recent times humans have been brutally exploited.

The copy part was a recognized right, then taken away.


>...the vast majority of software was written in garbage collected language

and even then recently it costed (us) quite a few months to blame JVM and later the default glibc memory allocator for running out native (not java heap memory) - had to exclude all possible native libs (zlib, zstd via jna), direct buffers, sockets, thread stacks and so on. Changing the malloc to jemalloc solved the issue, even though initially it was done for its debugging capabilities.

It's just a great memory allocator.


I'm never sure if I should be upset or happy when I've been debugging a problem for long enough that I finally decide to switch something out in order to improve visibility and that immediately solves the problem for entirely unexpected reasons. Particularly all the times when I couldn't readily discern why.


We changed to jemalloc first on a jvm service which we could never get to run in its kube memory limit. with jemalloc its been dead stable for years, and we made it the default for all jvm services


I sounded all legit until the comma after "solutioned". I suspect that might be a fake.


All of the examples read like: "The dude abides", except in a grotesque/parody way.


Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: