JVM 堆外內存詳解

Java 進程內存占用除了JVM 運行時數據區,還有直接內存(Direct Memory)區域及 JVM 程序自身也會占用內存

  • 直接內存(Direct Memory)區域:直接內存通過使用Native堆外內存來存儲數據,這意味著數據不會被JVM的垃圾回收機制自動回收。與JVM堆內存相比,直接內存的分配和釋放成本較高,因為它涉及與操作系統交互和內存管理的開銷,也可能導致OOM異常出現
  • JVM 程序自身:JVM本身是個本地程序,還需要其他的內存去完成各種基本任務,比如,JIT Compiler 在運行時對熱點方法進行編譯,就會將編譯后的方法儲存在 Code Cache 里面;GC 等功能需要運行在本地線程之中,類似部分都需要占用內存空間

Java 進程內存占用

JVM內存區域劃分詳見 Java 內存區域與內存溢出異常

堆外內存

JVM 的堆外內存是指分配在JVM堆之外的內存空間,它不受JVM的垃圾回收機制管理。 以下是幾種常見的JVM堆外內存:

  1. 直接字節緩沖區(Direct ByteBuffers):Direct ByteBuffer是JVM堆外內存的一種形式,它通過使用Native堆外內存來存儲數據。
  2. NIO(New I/O)內存映射文件(Memory-mapped Files):NIO提供了一種將文件映射到內存的方式,這種內存映射文件將文件的內容直接映射到堆外內存中,可以通過內存訪問的方式來讀寫文件。
  3. JNI(Java Native Interface):JNI允許Java程序與本地代碼進行交互,可以在本地代碼中分配和管理堆外內存。

堆外內存可以使用Native Memory Tracking 或 Arthas memory 進行監控及診斷

直接字節緩沖區

在實際使用中,Java 會盡量對 Direct Buffer 僅做本地 IO 操作,對于很多大數據量的 IO 密集操作,可能會帶來非常大的性能優勢,因為:

  • Direct Buffer 可以通過ByteBuffer.allocateDirect()方法來創建,它的數據存儲在堆外內存中,生命周期內內存地址都不會再發生更改,進而內核可以安全地對其進行訪問,很多 IO 操作會很高效
  • 減少了堆內對象存儲的可能額外維護工作,所以訪問效率可能有所提高

Direct Buffer 創建和銷毀過程中,都會比一般的堆內 Buffer 增加部分開銷,所以通常都建議用于長期使用、數據較大的場景。

可以使用JVM參數設定直接內存限制

-XX:MaxDirectMemorySize=512M

大多數垃圾收集過程中,都不會主動收集 Direct Buffer,它的垃圾收集過程,就是基于 Cleaner(一個內部實現)和幻象引用(PhantomReference)機制,其本身不是 public 類型,內部實現了一個 Deallocator 負責銷毀的邏輯。對它的銷毀往往要拖到full GC的時候,所以使用不當很容易導致OutOfMemoryError

Direct Buffer 回收方式:

  • 在應用程序中,顯式地調用System.gc()來強制觸發。
  • 另外一種思路是,在大量使用 Direct Buffer 的部分框架中,框架會自己在程序中調用釋放方法(Netty 就是這么做的,有興趣可以參考其實現PlatformDependent0)
  • 重復使用 Direct Buffer

NIO

Java NIO(New I/O)是Java提供的一套用于高效處理I/O操作的API,引入自JDK 1.4版本。相對于傳統的Java I/O(IO流)API,Java NIO提供了更靈活、更高效的非阻塞I/O操作方式,適用于構建高性能的網絡應用程序。

Java NIO的核心概念包括以下幾個部分:

  • 通道(Channel):通道是數據源和數據目標之間的連接,可以通過通道讀取和寫入數據。通道可以是雙向的,可以從通道中讀取數據,也可以向通道中寫入數據
  • 緩沖區(Buffer):緩沖區是一個固定大小的數據容器,用于存儲讀取和寫入的數據。通過緩沖區可以更高效地讀寫數據,避免頻繁的數據拷貝操作。緩沖區可以讀取和寫入不同類型的數據,如字節、字符、整數等
  • 選擇器(Selector):選擇器是用于多路復用非阻塞I/O操作的組件。可以通過選擇器同時管理多個通道,使得單線程可以處理多個通道的I/O操作,提高系統的性能和吞吐量

NIO提供了一種將文件映射到內存的方式,這種內存映射文件將文件的內容直接映射到堆外內存中。這種方式在處理大型文件時可以提供更高的性能和效率

JNI

使用JNI(Java Native Interface)可以在Java程序中通過調用本地代碼來使用JVM堆外內存。JNI提供了一種機制,使得Java程序可以與本地代碼進行交互,調用本地代碼中的函數和訪問本地內存

通過JNI,Java程序可以直接訪問和操作本地內存,例如在C或C++中使用malloc()free()函數進行內存分配和釋放

JNI操作JVM堆外內存具體步驟
  1. 定義本地方法:在Java類中聲明本地方法,使用native關鍵字標記。
public class NativeMemoryExample {public native void allocateMemory(int size);public native void freeMemory();
}
  1. 生成本地方法的頭文件:使用Java的javac命令編譯Java源文件,然后使用javah命令生成本地方法的頭文件。
javac NativeMemoryExample.java
javah NativeMemoryExample

這將生成名為NativeMemoryExample.h的頭文件

  1. 實現本地方法:在本地代碼中實現Java類中聲明的本地方法。在本地方法中可以使用C/C++等編程語言來操作堆外內存
#include "NativeMemoryExample.h"
#include <stdlib.h>JNIEXPORT void JNICALL Java_NativeMemoryExample_allocateMemory(JNIEnv *env, jobject obj, jint size) {void *buffer = malloc(size);// 使用buffer進行堆外內存操作
}JNIEXPORT void JNICALL Java_NativeMemoryExample_freeMemory(JNIEnv *env, jobject obj) {// 釋放之前分配的堆外內存free(buffer);
}
  1. 編譯本地代碼:使用C/C++編譯器將本地代碼編譯為共享庫(或動態鏈接庫)
gcc -shared -fpic -o libNativeMemoryExample.so NativeMemoryExample.c
  1. 加載本地庫:在Java程序中使用System.loadLibrary()方法加載本地庫
public class Main {static {System.loadLibrary("NativeMemoryExample");}public static void main(String[] args) {NativeMemoryExample example = new NativeMemoryExample();example.allocateMemory(1024);  // 調用本地方法分配堆外內存// ...example.freeMemory();  // 調用本地方法釋放堆外內存}
}

通過以上步驟,Java程序可以使用JNI調用本地方法,在本地代碼中進行對JVM堆外內存的分配和釋放操作。需要注意的是,在使用JNI時應謹慎管理內存,避免內存泄漏和溢出,確保正確地釋放分配的堆外內存


參考資料:

  1. Java Native Interface
  2. Direct Buffer
  3. Native Memory Tracking

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/160595.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/160595.shtml
英文地址,請注明出處:http://en.pswp.cn/news/160595.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大數據平臺實踐之CDH6.2.1+spark3.3.0+kyuubi-1.6.0

前言&#xff1a;關于kyuubi的原理和功能這里不做詳細的介紹&#xff0c;感興趣的同學可以直通官網&#xff1a;https://kyuubi.readthedocs.io/en/v1.7.1-rc0/index.html 下載軟件版本 wget http://distfiles.macports.org/scala2.12/scala-2.12.16.tgz wget https://archi…

pikachu_php反序列化

pikachu_php反序列化 源代碼 class S{var $test "pikachu";function __construct(){echo $this->test;} }//O:1:"S":1:{s:4:"test";s:29:"<script>alert(xss)</script>";} $html; if(isset($_POST[o])){$s $_POST[…

基于python人臉性別年齡檢測系統-深度學習項目

歡迎大家點贊、收藏、關注、評論啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代碼。 文章目錄 一項目簡介簡介技術組成1. OpenCV2. Dlib3. TensorFlow 和 Keras 功能流程 二、功能三、系統四. 總結 一項目簡介 # Python 人臉性別年齡檢測系統介紹 簡介 該系統基…

用idea搭建一個spring cloud微服務項目

以下是使用 IntelliJ IDEA 搭建 Spring Cloud 微服務項目的步驟&#xff1a; 創建一個新的 Maven 項目。 在 pom.xml 文件中添加以下依賴&#xff1a; <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-…

Android studio 遷移之后打開沒反應

把Android studio由d盤遷移到c盤&#xff0c;點擊沒反應&#xff1b; 需要把C:\Users\xxxx\AppData\Roaming\Google\AndroidStudio2022.3 目錄下的studio64.exe.vmoptions 修改為C:&#xff0c;刪除該文件會導致無法安裝app。 里面配置了一個

SpringMVC問題

文章目錄 SpringMVC運行流程MVC的概念與請求在MVC中的執行路徑&#xff0c;ResponsBody注解的用途SpringMVC啟動流程 SpringMVC運行流程 ? 客戶端&#xff08;瀏覽器&#xff09;發送請求&#xff0c;直接請求到 DispatcherServlet 。 ? DispatcherServlet 根據請求信息調用 …

SpringBoot問題

文章目錄 Springboot特性 Springboot特性 自動裝配&#xff1a;提供自動配置的“starter”項目對象模型&#xff08;POMS&#xff09;以簡化Maven配置。比如使用 MongoDB 時&#xff0c;只需加入 MongoDB 的 Starter 包&#xff0c;然后配置 的連接信息&#xff0c;就可以直接使…

【React-Router】路由導航

1. 概念 路由系統中的多個路由之間需要進行路由跳轉&#xff0c;并且在跳轉的同時有可能需要傳遞參數進行通信。 2. 聲明式導航 // /page/Login/index.jsimport { Link } from react-router-dom const Login () > {return <div>登錄頁{/* 解析成 a 鏈接 */}<Li…

php獲取表單以POST方式或GET方式提交的值

在php中存在兩個全局變量&#xff08;數組&#xff09;&#xff0c;其中$_GET數組用來記錄表單通過GET方式提交的數據&#xff0c;$_POST數組用來記錄表單通過POST方式提交的數據。 一、php獲取GET方式提交的值 在php中通過以下代碼來獲取&#xff1a; $_GET[name] //nam…

Windows平臺如何實現RTSP流二次編碼并添加動態水印后推送RTMP或輕量級RTSP服務

技術背景 我們在對接RTSP播放器相關的技術訴求的時候&#xff0c;遇到這樣的需求&#xff0c;客戶做特種設備巡檢的&#xff0c;需要把攝像頭拍到的RTSP流拉下來&#xff0c;然后添加動態水印后&#xff0c;再生成新的RTSP URL&#xff0c;供平臺調用。真個流程需要延遲盡可能…

Anthropic LLM論文閱讀筆記

研究時間&#xff1a;與Instrcut GPT同期的工作&#xff0c;雖然其比ChatGPT發布更晚&#xff0c;但是其實完成的時間比ChatGPT更早。與ChatGPT的應用區別&#xff1a;該模型比ChatGPT回答我不知道的概率更高。將強化學習用于大語言模型&#xff08;RLHF&#xff09;&#xff1…

6.基于蜻蜓優化算法 (DA)優化的VMD參數(DA-VMD)

代碼原理 基于蜻蜓優化算法 (Dragonfly Algorithm, DA) 優化的 VMD 參數&#xff08;DA-VMD&#xff09;是指使用蜻蜓優化算法對 VMD 方法中的參數進行自動調優和優化。 VMD&#xff08;Variational Mode Decomposition&#xff09;是一種信號分解方法&#xff0c;用于將復雜…

【數據結構】鏈表中二級指針的應用

&#x1f984;個人主頁:修修修也 &#x1f38f;所屬專欄:數據結構 ??操作環境:Visual Studio 2022 (注:為方便演示本篇使用的x86系統,因此指針的大小為4個字節) 目錄 &#x1f4cc;形參的改變不影響實參! 1.調用函數更改整型時傳值調用與傳址調用的區別 &#x1f38f;傳值…

微服務學習|初識Docker、使用Docker、自定義鏡像、DockerCompose、Docker鏡像倉庫

初識Docker 項目部署的問題 大型項目組件較多&#xff0c;運行環境也較為復雜&#xff0c;部署時會碰到一些問題 依賴關系復雜&#xff0c;容易出現兼容性問題 開發、測試、生產環境有差異 Docker如何解決依賴的兼容問題的? 將應用的Libs (函數庫)、Deps (依賴)配置與應用…

線性回歸的正則方法:嶺回歸和Lasso

線性回歸的正則方法包括嶺回歸&#xff08;Ridge Regression&#xff09;和Lasso回歸&#xff08;Least Absolute Shrinkage and Selection Operator Regression&#xff09;。這兩種方法都是為了解決線性回歸中可能存在的過擬合問題而提出的。 選擇使用嶺回歸還是Lasso回歸通常…

使用 goland 開發 golang 項目環境配置

方式1&#xff1a;使用 GOPATH 和 GOROOT 在 goland 中打開&#xff1a;Settings - Go&#xff0c;會看到 GOROOT、GOPATH&#xff0c;其相關解釋與配置如下&#xff1a; GOROOT&#xff1a;對應 go 的安裝路徑&#xff0c;例如&#xff1a;D:\go\binGOPATH&#xff1a;是我們…

JavaScript中的事件循環 為什么是微任務先運行

無意中看到這個問題&#xff0c;以下是個人的看法 1、性能和響應性&#xff1a; 微任務通常比宏任務執行得更快&#xff0c;因為微任務通常涉及更少的工作量。將微任務放在宏任務之前可以盡早執行那些需要快速響應的任務&#xff0c;提高系統的響應性能。 2、Promise 的異步特…

3d標簽云實現過程(tagcloud.js)同步原生和 vue

寫在前面 本來是沒有準備寫這個知識點&#xff0c;但是下載這個 js 的時候發現很多都是要錢或者是積分的&#xff0c;我就不明白了一個開源了這么久的 js 怎么還有人拿來掙錢的&#xff0c;同時還有一些只有原生 html 的例子&#xff0c;但是現在都是 框架主導的一些項目&#…

【Exception】Error: Dynamic require of “path“ is not supported

Talk is cheap, show me the code. 環境 | Environment kversionOSwindows 11Node.jsv18.14.2npm9.5.0vite5.0.0vue3.3.8 報錯日志 | Error log >npm run dev> app10.0.0 dev > viteERROR failed to load config from C:\code\frontend\app1\vite.config.js …

【LeetCode二叉樹進階題目】606,102,107

二叉樹進階題目 606. 根據二叉樹創建字符串解題思路及實現 102. 二叉樹的層序遍歷解題思路及實現 107. 二叉樹的層序遍歷 II解題思路及實現 606. 根據二叉樹創建字符串 描述 給你二叉樹的根節點 root &#xff0c;請你采用前序遍歷的方式&#xff0c;將二叉樹轉化為一個由括號…