Memory leak + solution

Krzysztof Strasburger (strasbur@chkw386.ch.pwr.wroc.pl)
Fri, 18 Apr 97 14:34


Hi all!
I just switched to 2.0.30 and found an old good bug known from the 1.2.13
kernel. Yesterday I started my program on the 16 MB RAM + 16 MB swap machine.
The program uses about 16 MB of memory. In the meantime I switched to the
other VC (running X) and played xtetris, then logged out. The machine was
quite responsible, despite of swapping. After switching to the text console
I ran top. The amount of free swap was lower and lower... and lower...
No new programs were run and my program did not allocate more memory, but
free space disappeared. After quitting top I could not run any program, getting
"Could not load interpreter" "Can't map libxxx.so..." and "Segmentation fault"
messages.
I discovered similar problem over 1 year ago under 1.2.13. The solution
was introduction of additional variable counting pages in the swap cache.
I'm curious that this bug has not been fixed for so long time.
My patch (against 2.0.30) changes additionally the policy of checking
for free memory in vm_enough_memory (currently if you have 128 MB of memory
frozen in buffers and your program tries to allocate 96 MB of memory, it
can't do it - the allocator thinks there is only 64 MB of memory available).
If you don't like it, remove it by hand.
All comments are welcome.

Krzysztof Strasburger

diff -u -r linux.orig/include/linux/swap.h linux/include/linux/swap.h
--- linux.orig/include/linux/swap.h Mon Jun 3 14:38:37 1996
+++ linux/include/linux/swap.h Fri Apr 18 17:11:22 1997
@@ -34,6 +34,7 @@

extern int nr_swap_pages;
extern int nr_free_pages;
+extern int nr_swap_cache_pages;
extern atomic_t nr_async_pages;
extern int min_free_pages;
extern int free_pages_low;
@@ -114,8 +115,10 @@
#endif
entry = xchg(swap_cache + index, 0);
#ifdef SWAP_CACHE_INFO
- if (entry)
+ if (entry) {
swap_cache_find_success++;
+ nr_swap_cache_pages--;
+ }
#endif
return entry;
}
@@ -133,6 +136,7 @@
swap_cache_del_success++;
#endif
swap_free(entry);
+ nr_swap_cache_pages--;
return 1;
}
return 0;
diff -u -r linux.orig/mm/mmap.c linux/mm/mmap.c
--- linux.orig/mm/mmap.c Fri Dec 6 22:09:24 1996
+++ linux/mm/mmap.c Fri Apr 18 17:12:08 1997
@@ -55,9 +55,10 @@
long freepages;
freepages = buffermem >> PAGE_SHIFT;
freepages += page_cache_size;
- freepages >>= 1;
+/* freepages >>= 1;*/
freepages += nr_free_pages;
freepages += nr_swap_pages;
+ freepages += nr_swap_cache_pages;
freepages -= MAP_NR(high_memory) >> 4;
return freepages > pages;
}
diff -u -r linux.orig/mm/swap_state.c linux/mm/swap_state.c
--- linux.orig/mm/swap_state.c Wed Mar 13 14:17:23 1996
+++ linux/mm/swap_state.c Fri Apr 18 17:12:11 1997
@@ -32,6 +32,8 @@
*/
unsigned long *swap_cache;

+int nr_swap_cache_pages = 0;
+
#ifdef SWAP_CACHE_INFO
unsigned long swap_cache_add_total = 0;
unsigned long swap_cache_add_success = 0;
@@ -64,6 +66,7 @@
#ifdef SWAP_CACHE_INFO
swap_cache_add_success++;
#endif
+ nr_swap_cache_pages++;
return 1;
}
return 0;
diff -u -r linux.orig/mm/swapfile.c linux/mm/swapfile.c
--- linux.orig/mm/swapfile.c Thu Apr 10 23:47:14 1997
+++ linux/mm/swapfile.c Fri Apr 18 17:12:12 1997
@@ -570,6 +570,7 @@
++val->totalswap;
}
}
+ val->freeswap += nr_swap_cache_pages;
val->freeswap <<= PAGE_SHIFT;
val->totalswap <<= PAGE_SHIFT;
return;