![0dec25dd2f3e7b930b6468b16fa555f3.png](https://i-blog.csdnimg.cn/blog_migrate/c00053920fc03275dda21ba2bcebae8c.jpeg)
在说JAVA语言的内存分配之前,我们先聊聊OS的Memory Management,这是学习操作系统课程的一个重要内容。从这里开始理解内存分配有利于理解的更深入。
我们知道物理内存是由page 和segment 方式混合管理的,映射的过程如下图所示:
![d4d42c6d5c2b1ab22dfcdcd2db8d4073.png](https://i-blog.csdnimg.cn/blog_migrate/0ebfb20084010bf681a701345982bb85.png)
从物理地址到虚地址的映射后,一个进程的内存布局大概是下图这个样子的。
![859761871c65a6bbb1d4eb8a260a0588.png](https://i-blog.csdnimg.cn/blog_migrate/224f513c45c73c4f854176dabd99eb03.jpeg)
Stack区用于存储local variable和函数参数,Heap区用于存储动态分配的内存,即malloc分配的内存。默认由glibc ptmalloc2管理。当然也可以替换成性能更好的tcmalloc和jemalloc。
JVM的内存管理可以分成两块,一块是native memory的管理,一块就是JAVA语言的管理。JAVA语言的内存管理当然最终基于native memory来实现。
下图是从JAVA语言看内存布局。
![52c619a64eff2eba800922cf3add83e2.png](https://i-blog.csdnimg.cn/blog_migrate/3129059bbdc36874a0ec31d939d3a6f1.png)
其中堆内存的布局又是如下的:
![6ad5f9e903083afa1a69acc8972074ba.png](https://i-blog.csdnimg.cn/blog_migrate/7a6254e99b61a1632bb3c0e0f53354ef.jpeg)
为了提高多线程内存分配的性能,避免在内存分配阶段有锁竞争。在Eden区其实存在TLAB(Thread local allocator buffer)区。因此,针对java语言中的新建一个对象(内存分配),存在两种情况。
- The thread gets a new TLAB
- The object is allocated outside TLAB
TLAB的大小通常是有限的,如果线程中经常分配一个大对象/大数组,TLAB放不下,就会在Eden的outside TLAB分配,竞争就会加剧,性能就会下降。因此,建议线程中如果有大对象的频繁分配,建议减小这个大对象的尺寸,或者分成两次分配。
下面提供实际做内存分配的函数。
// JDK 7-9
_ZN11AllocTracer33send_allocation_in_new_tlab_event
_ZN11AllocTracer34send_allocation_outside_tlab_event
// JDK 10+
_ZN11AllocTracer27send_allocation_in_new_tlab
_ZN11AllocTracer28send_allocation_outside_tlab