解决UDT中内存下不去的问题

简介: 使用UDT库,编写简单的网络通信程序,发现了一个问题,关闭一部分连接后,程序占用内存并没有变化。      比如先连接500个,再连接另500个,先关掉后面500个,程序占用内存降一半,再关掉500个,程序占用内存降到0.1。
     使用UDT库,编写简单的网络通信程序,发现了一个问题,关闭一部分连接后,程序占用内存并没有变化。
     比如先连接500个,再连接另500个,先关掉后面500个,程序占用内存降一半,再关掉500个,程序占用内存降到0.1。然而,如果先关掉前面500个,程序占用内存不会发生变化,只有等再关掉后面500个,程序内存才会降到0.1。
     换个顺序就降不了,这很奇怪,很“玄学”。
     跟踪代码至底层,该有的释放都有,这是为什么?灵机一动想到可能与linux内存管理机制有关,果不其然,linux中给程序分配堆内存后,当程序free,内存并不会马上还给系统,而是交由Ptmalloc管辖,这样程序再需要内存的时候,就可以直接向Ptmalloc取,不用再向系统申请,效率较高。Ptmalloc也不是说就不把内存还给系统了,返回内存的机制叫“内存收缩”,当堆顶的空闲内存大于收缩阈值(默认是128KB)时,即可触发。注意,这边要求的空闲内存必须位于堆顶,所以如果堆顶的内存不释放,堆底的内存再怎么释放都触发不了内存收缩,这就导致了那个玄学的结果。
     因此,在代码里添加这么一句mallopt(M_MMAP_THRESHOLD, 128);,M_MMAP_THRESHOLD是mmap分配阈值,当程序所要内存大于M_MMAP_THRESHOLD时,直接调用mmap()分配内存,free的时候,会直接调用munmap()将内存还给操作系统,不再被Ptmalloc缓存管理。所以连接关闭后,内存就能下去了。
     这样做的缺点是需要的内存更多,需要的内存数量随M_MMAP_THRESHOLD数值的减少而增多,所以需要选个合适的数字。且这些内存不再重用,分配效率也会比较低。
     然而,对于分配长生命周期的大内存块,使用mmap()才是最高效的,Ptmalloc并不擅长管理长生命周期的内存,尤其是持续不定期分配和释放长生命周期的内存,这会导致内存暴增。
目录
相关文章
|
7月前
|
存储 缓存 Java
Java中的缓冲流提升I/O性能,通过内存缓冲区减少对硬件访问
【6月更文挑战第22天】Java中的缓冲流提升I/O性能,通过内存缓冲区减少对硬件访问。`BufferedInputStream`和`BufferedOutputStream`用于字节流,缓存数据批量读写。`BufferedReader`和`BufferedWriter`处理字符流,支持按行操作。使用后务必关闭流。
80 3
|
8月前
|
缓存 Java
直接内存(Direct Memory)牛刀小试
直接内存(Direct Memory)牛刀小试
52 0
java Nio(二): Buffer(缓冲区)的数据存取
java Nio(二): Buffer(缓冲区)的数据存取
java Nio(二): Buffer(缓冲区)的数据存取
|
存储 Java 调度
【JVM原理探索】分析堆外内存(Direct Memory)使用和分析
【JVM原理探索】分析堆外内存(Direct Memory)使用和分析
1497 0
【JVM原理探索】分析堆外内存(Direct Memory)使用和分析
|
Java
让你的对象跑出内存,写入到磁盘或者进行网络传输,一文掌握Java对象序列化
让你的对象跑出内存,写入到磁盘或者进行网络传输,一文掌握Java对象序列化
162 0
IO流的字节流的缓冲和非缓冲方式的区别及性能对比
IO流的字节流的缓冲和非缓冲方式的区别及性能对比
271 0
|
存储 算法 安全
JVM栈上分配对象内存与逃逸分析原理分析(Escape Analysis)
JVM栈上分配对象内存与逃逸分析原理分析(Escape Analysis)
172 0
JVM栈上分配对象内存与逃逸分析原理分析(Escape Analysis)
运用内存操作流实现IO操作 | 带你学《Java语言高级特性》之六十一
文件操作流能够实现对文件内容的读写操作,若是碰到了不希望产生文件的IO操作,显然是不能实现的,此时就需要用到内存操作流程。本节将为读者介绍内存操作流的相关知识。
运用内存操作流实现IO操作 | 带你学《Java语言高级特性》之六十一
|
网络安全
UDT的连接建立和释放
连接的建立和释放 UDT有两种建立连接的方式,C/S模式和聚合模式,在聚合模式中,各UDT Socket会同时向各方发出连接请求,类似于P2P模式。
1164 0