操作系統對單個進程的內存限制
* 32位系統下,單個進程默認來可以使用2GB內存;
### 本地內存/直接內存\(Direct Memory\)
直接內存并不是虛擬機運行時數據區的一部分,也不是Java虛擬機規范中定義的內存區域,但是這部分內存也被頻繁的使用;
內存不足時拋出OutOfMemoryError或 者OutOfMemoryError:Direct buffer memory
#### 特性
* -XX:MaxDirectMemorySize 最大值,默認和Java堆最大值一樣
* 不屬于運行時數據區
* 本機直接內存的分配不受Java堆大小的限制,僅受本機總內存大小以及處理器尋址空間的限制
說明:在JDK 1.4 中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(Buffer)的I/O 方式,它可以使用Native函數庫直接分配堆外內存,然后通過一個存儲在Java 堆里面的DirectByteBuffer 對象作為這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因為避免了在Java 堆和Native 堆中來回復制數據。
_**注意使用Native函數庫分配堆外內存,通過JAVA堆DirectByteBuffer引用堆外內存**_
直接內存是一塊物理內存,專門用于JVM和IO設備打交道,Java底層使用C語言的API調用操作系統與IO設備進行交互。
例如,Java內存中有一個字節數組,現在調用流將它寫入磁盤文件,那么JVM首先會將這個字節數組先拷貝一份到堆外內存中,然后調用C語言API指明將某個連續地址范圍的數據寫入磁盤。
讀操作也是類似,而JVM額外做的拷貝工作也是有意義的,因為JVM是基于自動垃圾回收機制運行的,所有內存中的數據會在GC時不停的被移動,如果你調用系統API告訴操作系統將內存某某位置的內存寫入磁盤,而此時發生GC移動了該部分數據,GC結束后操作系統是不是就寫錯數據了。
所以,JVM對于與外圍IO設備交互的情況下,都會將內存數據復制一份到堆外內存中,然后調用系統API間接的寫入磁盤,讀也是類似的。由于堆外內存不受GC管理,所以用完一定得記得釋放
### 直接內存(堆外內存)與堆內存比較
* 直接內存申請空間耗費更高的性能,當頻繁申請到一定量時尤為明顯;
* 直接內存IO讀寫的性能要優于普通的堆內存,在多次讀寫操作的情況下差異明顯;
### 堆外內存
* 直接內存:可通過-XX:MaxDirectMemorySize調整大小,內存不足時拋出OutOf-MemoryError或 者OutOfMemoryError:Direct buffer memory;
* 線程堆棧:可通過-Xss調整大小,內存不足時拋出StackOverflowError(如果線程請求的棧深度大 于虛擬機所允許的深度)或者OutOfMemoryError(如果Java虛擬機棧容量可以動態擴展,當棧擴展時無法申請到足夠的內存);
* Socket緩存區:每個Socket連接都Receive和Send兩個緩存區,分別占大約37KB和25KB內存,連接多的話這塊內存占用也比較可觀。如果無法分配,可能會拋出IOException:Too many open files異常;
* JNI代碼:如果代碼中使用了JNI調用本地庫,那本地庫使用的內存也不在堆中,而是占用Java虛擬機的本地方法棧和本地內存的;
* 虛擬機和垃圾收集器:虛擬機、垃圾收集器的工作也是要消耗一定數量的內存的;
- 前言
- Write once, run anywhere
- 概述
- JAVA虛擬機
- JVM整體結構
- JVM架構模型
- JVM虛擬機分類
- HotSpot VM
- JRockit
- IBM-J9
- Azul/zing VM
- Taobao VM
- Dalvik VM
- Graal VM
- JAVA源碼編譯機制
- Javac編譯器
- 分析和輸入到符號表
- 注解處理
- 語義分析和生成class文件
- ECJ編譯器
- 類執行機制
- 字節碼解釋執行
- 棧頂緩存
- 部分棧幀共享
- 編譯執行
- 即時編譯器
- C1 Compiler
- C2 Compiler
- Graal編譯器
- C1與C2編譯器
- AOT
- 編譯優化
- 字符串優化
- 方法內聯
- 逃逸分析
- 同步消除
- 標量替換
- 棧上分配
- 去虛擬化/逆優化
- 多層編譯
- JVM編譯策略
- OSR編譯
- 冗余削除
- CodeCache
- 常量編譯優化
- JVM運行時數據區
- 程序計數器
- JAVA虛擬機棧
- 棧幀
- 局部變量表
- 操作數棧
- 本地方法棧
- Java調用native方法
- JVM Stacks && Native Stacks
- 堆-Heap
- 方法區(Method Area)
- 運行時常量池
- 常量傳播優化
- MetaSpace
- 直接內存
- StackOverflowError
- 遞歸方法
- OutOfMemoryError
- 本地內存溢出
- 執行引擎
- 運行時數據區關聯關系
- jdk8內存結構
- JMM內存模型
- JAVA內存模型
- JMM八種操作指令
- 內存屏障
- 指令重排
- as-if-serial語義
- Happen-Before規則
- 數據依賴性
- 原子性、可見性與有序性
- 偽共享
- CPU三級緩存
- 緩存行
- MESI協議
- Java中的偽共享
- ConcurrentHashMap偽共享解決方案
- 虛擬機對象
- 對象創建原理
- 對象內存布局
- 對象頭
- 實例數據
- 對象的訪問定位
- 垃圾收集器與內存分配策略
- GC相關概念
- TLAB
- JVM GC工作原理
- 內存管理
- JAVA引用分類
- 死亡標記
- 回收方法區
- 三色標記算法
- 垃圾收集算法
- 標記-清除算法
- 標記-整理算法
- 復制算法
- 分代收集算法
- HotSpot算法實現
- STW
- 垃圾收集器
- 常見的垃圾收集器
- 垃圾收集器分類
- Serial收集器
- Serial Old收集器
- ParNew收集器
- Parallel Scavenge收集器
- Parallel Old收集器
- CMS收集器
- CMS完整收集過程
- Card Table
- G1收集器
- 分代收集
- 空間整合
- 可預測的停頓時間模型
- G1&CMS
- 主要參數說明
- G1適用場景
- Remembered Set
- G1垃圾回收的過程
- G1優化建議
- Shenandoah
- ZGC
- 垃圾收集器特點
- GC日志
- GC策略的評價指標
- jvm card table數據結構
- 對象生存軌跡
- 類文件結構
- 魔數
- 版本號
- 常量池
- 訪問標志
- 父類索引
- 接口集合
- 字段集合
- 方法集合
- 屬性集合
- 類加載機制與類的初始化
- Java代碼執行流程
- 類加載過程
- 抽象類ClassLoader
- 常見類加載器
- BootstrapClassLoader
- 自定義類加載器
- 線程上下文類加載器
- 雙親委派模型
- Tomcat類加載機制
- ServiceLoader
- 類的初始化
- 常見的JVM類加載異常
- ClassNotFoundException
- NoClassDefFoundError
- LinkageError
- ClassCastException
- 虛擬機性能調優監控與故障處理工具
- CPU利用率高/飆升
- 排查及解決方案
- 上下文切換
- GC問題定位解決方案
- prommotion failed
- FullGC頻繁
- youngGC
- 內存問題
- 內存溢出和內存泄漏
- 內存溢出
- 棧溢出
- 堆溢出
- 對外內存溢出
- 內存泄漏
- 磁盤問題
- 線上問題解決方案
- 不定期出現的接口耗時現象
- 線程池異常
- 死鎖問題
- JVM調優
- jvm參考配置
- jvm-jstat
- jvm-jmap
- jvm-jstack
- jinfo
- jps
- 虛擬機的退出
- Shutdown Hook
- JVM指令
- 附錄
- 常用JVM指令
- Class文件版本號
- Class文件格式
- 方法訪問標識
- jvm常量池
- 類或接口的訪問標識
- 描述符標識字符含義
- 字段訪問標識
- Java程序與Docker容器環境
- 基準測試