Just to explain it a bit more. Let's have a look at a 32 bit linux kernel and how sets up the memory layout of a running program:
Since we have paging enabled on modern operating systems, the CPU never ever sees physical memory addresses. It always sees virtual addresses and the MMU (which is part of the CPU) translates these addresses into its physical representation.
So, the kernel runs in its virtual address space (it actually maps the whole phsyical memory into virtual memory) and each process runs in its own virtual address space. When ASLR is disabled, the virtual address space of a running program always looks the same. There is:
- the text segment: it includes the memory mapped file of the executable file
- the data segment: static variables, like strings
- the bss segment: there are unitialized variabled, like pointers
- the kernel: It avtually maps itself in the address space of a program in order to enable jumping in kernel space for system calls.
- the stack: currently active functions allocate stackframes here
- the heap: memory which gets allocated by
- the mmap segment: Where shared libraries and memory mapped files live
The advantage of this concept is, that every segment can live in virtual reality. The kernel can do demand paging. That means, it can allocate a really large region somwhere on the heap or in the mmap segment and the program thinks: hey I got really much memory, awesome. In real reality, the kernel allocates physical memory when its needed.
The go language adds some fancy abstraction over these low level concepts. When we do some hashing of large files or allocate buffers for something, then the memory is virtually allocated but the kernel can decide when to actually allocate physical RAM. So, just ignore the virtual memory column and look at the RSS column to find out how much RAM syncthing uses. The virtual memory column in htop actually is the sum of all blue reagions in the picture above; RSS is the sum of the actually allocated pages.