JVM的Heap Memory和Native Memory

JVM管理的內存能夠整體劃分爲兩部分:Heap Memory和Native Memory。前者咱們比較熟悉,是供Java應用程序使用的;後者也稱爲C-Heap,是供JVM自身進程使用的。Heap Memory及其內部各組成的大小能夠經過JVM的一系列命令行參數來控制,在此不贅述。Native Memory沒有相應的參數來控制大小,其大小依賴於操做系統進程的最大值(對於32位系統就是3~4G,各類系統的實現並不同),以及生成的Java字節碼大小、建立的線程數量、維持java對象的狀態信息大小(用於GC)以及一些第三方的包,好比JDBC驅動使用的native內存。html

Native Memory裏存些什麼?

  1. 管理java heap的狀態數據(用於GC);
  2. JNI調用,也就是Native Stack;
  3. JIT(即便編譯器)編譯時使用Native Memory,而且JIT的輸入(Java字節碼)和輸出(可執行代碼)也都是保存在Native Memory;
  4. NIO direct buffer。對於IBM JVM和Hotspot,均可以經過-XX:MaxDirectMemorySize來設置nio直接緩衝區的最大值。默認是64M。超過這個時,會按照32M自動增大。
  5. 對於IBM的JVM某些版本實現,類加載器和類信息都是保存在Native Memory中的。

DirectBuffer的好處

DirectBuffer訪問更快,避免了從HeapBuffer還須要從java堆拷貝到本地堆,操做系統直接訪問的是DirectBuffer。DirectBuffer對象的數據實際是保存在native heap中,可是引用保存在HeapBuffer中。
另外,DirectBuffer的引用是直接分配在堆得Old區的,所以其回收時機是在FullGC時。所以,須要避免頻繁的分配DirectBuffer,這樣很容易致使Native Memory溢出。java

爲何會內存溢出?

簡單理解java process memory = java heap + native memory。所以內存溢出時,首先要區分是堆內存溢出仍是本地內存溢出。Native Memory本質上就是由於耗盡了進程地址空間。對於HotSpot JVM來書,不斷的分配直接內存,會致使以下錯誤信息:Allocated 1953546760 bytes of native memory before running outlinux

參考資料:

http://www.ibm.com/developerworks/library/j-nativememory-linux/index.html
http://www.techpaste.com/2012/07/steps-debugdiagnose-memory-memory-leaks-jvm/
https://sourcevirtues.wordpress.com/2013/01/14/java-heap-space-and-native-heap-problems/
http://www.theotherian.com/2013/08/understanding-javas-native-heap-or-c-heap.html
http://www.ibm.com/developerworks/library/l-kernel-memory-access/
http://www.ibm.com/developerworks/library/j-zerocopy/
http://en.wikipedia.org/wiki/Direct_memory_accessweb