溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么理解并掌握J(rèn)ava虛擬機(jī)內(nèi)存區(qū)

發(fā)布時(shí)間:2021-11-03 17:38:47 來(lái)源:億速云 閱讀:105 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容主要講解“怎么理解并掌握J(rèn)ava虛擬機(jī)內(nèi)存區(qū)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“怎么理解并掌握J(rèn)ava虛擬機(jī)內(nèi)存區(qū)”吧!

一、方法區(qū)(Method Area)

方法區(qū)的概念

方法區(qū)又叫靜態(tài)區(qū),存放的是已加載的類的基本信息、常量、靜態(tài)變量等。它是各個(gè)線程共享區(qū)域。

比方說我們?cè)趯?Java  代碼時(shí),每個(gè)線程度可以訪問同一個(gè)類的靜態(tài)變量對(duì)象。由于使用反射機(jī)制的原因,虛擬機(jī)很難推測(cè)哪那個(gè)類信息不再使用,因此這塊區(qū)域的回收很難。

靜態(tài)塊和非靜態(tài)塊有什么區(qū)別?

  • 類(Class)和對(duì)象(Object)的區(qū)別與聯(lián)系?

  • 為什么靜態(tài)塊中不能使用 this、super 關(guān)鍵字?

  • 為什么 java 的靜態(tài)方法可以直接用類名調(diào)用?

方法區(qū)的特點(diǎn)

  • 線程間共享區(qū)域

方法區(qū)的異常

對(duì)這塊區(qū)域主要是針對(duì)常量池回收,值得注意的是 JDK1.7 已經(jīng)把常量池轉(zhuǎn)移到堆里面了。同樣,當(dāng)方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí),會(huì)拋出  OutOfMemoryError。制造方法區(qū)內(nèi)存溢出,注意,必須在 JDK1.6及之前版本才會(huì)導(dǎo)致方法區(qū)溢出,原因后面解釋,執(zhí)行之前,可以把虛擬機(jī)的參數(shù)  -XXpermSize 和 -XX:MaxPermSize 限制方法區(qū)大小。

代碼清單如下:

public static void printOOM() {  List<String> list = new ArrayList<String>();  int i = 0;  while (true) {  list.add(String.valueOf(i).intern());  } }

輸出異常結(jié)果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  at java.util.Arrays.copyOf(Arrays.java:2245)  at java.util.Arrays.copyOf(Arrays.java:2219)  at java.util.ArrayList.grow(ArrayList.java:242)  at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)  at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)  at java.util.ArrayList.add(ArrayList.java:440)  at com.vprisk.knowledgeshare.MethodAreExample.main(MethodAreExample.java:15)  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:606)  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

關(guān)于 String 的 intern() 函數(shù)intern() 的作用:

如果當(dāng)前的字符串在常量池中不存在,則放入到常量池中。

上面的代碼不斷將字符串添加到常量池,最終肯定會(huì)導(dǎo)致內(nèi)存不足,拋出方法區(qū)的 OOM。解釋一下,為什么必須將上面的代碼在 JDK1.6 之前運(yùn)行。我們前面提到  JDK1.7 后,把常量池放入到堆空間中,這導(dǎo)致 intern() 函數(shù)的功能不同,代碼清單如下:

public static void testInternMethod(){  String str1 =new StringBuilder("hua").append("chao").toString();  System.out.println(str1.intern()==str1);  String str2=new StringBuilder("ja").append("va").toString();  System.out.println(str2.intern()==str2); }

在場(chǎng)景 jdk6,輸出結(jié)果:

false , false

在場(chǎng)景 jdk7,輸出結(jié)果:

true , false

為什么了?

原因是在 JDK 1.6 中,intern() 方法會(huì)把首次遇到的字符串實(shí)例復(fù)制到常量池中,返回的也是常量池中的字符串的引用,而  StringBuilder 創(chuàng)建的字符串實(shí)例是在堆上面,所以必然不是同一個(gè)引用,返回false。在 JDK 1.7 中,intern  方法不再?gòu)?fù)制實(shí)例,常量池中只保存首次出現(xiàn)的實(shí)例的引用,因此intern() 返回的引用和由 StringBuilder 創(chuàng)建的字符串實(shí)例是同一個(gè)。為什么對(duì)  str2 比較返回的是 false呢?這是因?yàn)?,JVM 中內(nèi)部在加載類的時(shí)候,就已經(jīng)有”java”這個(gè)字符串,不符合“首次出現(xiàn)”的原則,因此返回  false。

方法區(qū)的作用

方法區(qū)存放的是類信息、常量、靜態(tài)變量等,是各個(gè)線程共享區(qū)域。

方法區(qū)的運(yùn)用

通過過設(shè)置虛擬機(jī)的參數(shù)-XXpermSize 以及 -XX:MaxPermSize 限制方法區(qū)大小。

二、虛擬機(jī)棧(VM Stack)

虛擬機(jī)棧的概念

Java 方法執(zhí)行的內(nèi)存模型:

每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀  (StackFrame)用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法被調(diào)用直至執(zhí)行完成的過程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過程

局部變量表

局部變量表存放了編譯器克制的各種基本數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)、對(duì)象引用(Object  reference)和字節(jié)碼指令地址(returnAddress 類型)。

操作棧

操作數(shù)棧也常被稱為操作棧,它是一個(gè)后入先出(Last In First Out, LIFO)棧。同局部變量表一樣,操作數(shù)棧的最大深度也在編譯的時(shí)候被寫入到  Code 屬性的max_stacks 數(shù)據(jù)項(xiàng)之中。操作數(shù)棧的每一個(gè)元素可以是任意的 Java 數(shù)據(jù)類型,包括 long 和 double。32  位數(shù)據(jù)類型所占的棧容量為 1,64 位數(shù)據(jù)類型所占的棧容量為 2。在方法執(zhí)行的任何時(shí)候,操作數(shù)棧的深度都不會(huì)超過在 max_stacks  數(shù)據(jù)項(xiàng)中設(shè)定的最大值。

當(dāng)一個(gè)方法剛剛開始執(zhí)行的時(shí)候,這個(gè)方法的操作數(shù)棧是空的,在方法的執(zhí)行過程中,會(huì)有各種字節(jié)碼指令向操作數(shù)棧中寫入和提取內(nèi)容,也就是入棧出棧操作。例如,在做算術(shù)運(yùn)算的時(shí)候是通過操作數(shù)棧來(lái)進(jìn)行的,又或者在調(diào)用其他方法的時(shí)候是通過操作數(shù)棧來(lái)進(jìn)行參數(shù)傳遞的。

舉個(gè)例子,整數(shù)加法的字節(jié)碼指令 iadd  在運(yùn)行的時(shí)候要求操作數(shù)棧中最接近棧頂?shù)膬蓚€(gè)元素已經(jīng)存入了兩個(gè)int型的數(shù)值,當(dāng)執(zhí)行這個(gè)指令時(shí),會(huì)將這兩個(gè)int值和并相加,然后將相加的結(jié)果入棧。

操作數(shù)棧中元素的數(shù)據(jù)類型必須與字節(jié)碼指令的序列嚴(yán)格匹配,在編譯程序代碼的時(shí)候,編譯器要嚴(yán)格保證這一點(diǎn),在類校驗(yàn)階段的數(shù)據(jù)流分析中還要再次驗(yàn)證這一點(diǎn)。再以上面的  iadd 指令為例,這個(gè)指令用于整型數(shù)加法,它在執(zhí)行時(shí),最接近棧頂?shù)膬蓚€(gè)元素的數(shù)據(jù)類型必須為int 型,不能出現(xiàn)一個(gè) long 和一個(gè)float 使用 iadd  命令相加的情況。

動(dòng)態(tài)鏈接

每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用,持有這個(gè)引用是為了支持方法調(diào)用過程中的動(dòng)態(tài)連接。我們知道 Class  文件的常量池有存有大量的符號(hào)引用,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號(hào)引用為參數(shù)。這些符號(hào)引用一部分會(huì)在類加載階段或第一次使用的時(shí)候轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化稱為靜態(tài)解析。另外一部分將在每一次的運(yùn)行期間轉(zhuǎn)化為直接引用,這部分稱為動(dòng)態(tài)連接。

虛擬機(jī)棧的特點(diǎn)

  • 線程私有

  • 生命周期與線程相同

虛擬機(jī)棧的異常

一種是 StackOverflowError

當(dāng)前線程如果請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度時(shí),則會(huì)拋出該異常。例如,將一個(gè)函數(shù)反復(fù)遞歸自己,最終會(huì)出現(xiàn)棧溢出錯(cuò)誤(StackOverflowError)。

代碼清單如下:

public class StackOverflowErrorDemo {  public static void main(String []args){  printStackOverflowError();  }  public static void printStackOverflowError(){  printStackOverflowError();  } }

輸出異常結(jié)果:

Exception in thread "main" java.lang.StackOverflowError stack length:9482  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)  at com.itech.jvm.demo.StackOverflowErrorDemo.printStackOverflowError(StackOverflowErrorDemo.java:22)

需要說明的是,在單個(gè)線程環(huán)境下,無(wú)論是棧幀太大,還是虛擬機(jī)棧容量太小,當(dāng)內(nèi)存無(wú)法分配時(shí),虛擬機(jī)都會(huì)拋出 StackOverflowError  異常。

一種是 OOM 異常

當(dāng)虛擬機(jī)棧支持動(dòng)態(tài)擴(kuò)展時(shí),如果無(wú)法申請(qǐng)到足夠多的內(nèi)存時(shí)就會(huì)拋出 OOM 異常。

代碼清單如下:

public class VMOOMDemo {  public static void main(String[] args) throws Throwable {  VMOOMDemo demo = new VMOOMDemo();  demo.printVMOOM();  }  public void printVMOOM() {  while (true) {  new Thread() {  public void run() {  while (true) {  }  }  }.start();  }  } }

這個(gè)例子慎用...

本例通過不斷地建立線程的方式產(chǎn)生內(nèi)存溢出異常。但是,這樣產(chǎn)生的內(nèi)存溢出異常與棧空間是否足夠大并不存在任何聯(lián)系,或者準(zhǔn)確地說,在這種情況下,給每個(gè)線程的棧分配的內(nèi)存越大,反而越容易產(chǎn)生內(nèi)存溢出異常。其原因是操作系統(tǒng)分配給每個(gè)進(jìn)程的內(nèi)存是有限制的,如  32 位的Windows 限制為 2 GB。。

虛擬機(jī)棧的作用

用于存儲(chǔ)局部變量、操作棧、動(dòng)態(tài)鏈接、方法出口

虛擬機(jī)棧的運(yùn)用

對(duì)于 32 位的 jvm,默認(rèn)大小為 256 kb, 而 64 位的 jvm, 默認(rèn)大小為 512 kb, 可以通過 -Xss  設(shè)置虛擬機(jī)棧的最大值。不過如果設(shè)置過大,會(huì)影響到可創(chuàng)建的線程數(shù)量。

三、本地方法棧(Native Method Stack)

本地方法棧的概念

本地方法棧與虛擬機(jī)棧所發(fā)揮的作用很相似,他們的區(qū)別在于虛擬機(jī)棧為執(zhí)行Java代碼方法服務(wù),而本地方法棧是為 Native  方法服務(wù)。與虛擬機(jī)棧一樣,本地方法棧也會(huì)拋出 StackOverflowError 和 OutOfMemoryError 異常。

本地方法棧的特點(diǎn)

  • 線程私有

  • 為 Native 方法服務(wù)

本地方法棧的異常

與虛擬機(jī)棧一樣,本地方法棧也會(huì)拋出 StackOverflowError 和 OutOfMemoryError 異常。

本地方法棧的作用

  • 與 java 環(huán)境外交互

有時(shí) java 應(yīng)用需要與 java 外面的環(huán)境交互。這是本地方法存在的主要原因,你可以想想 java  需要與一些底層系統(tǒng)如操作系統(tǒng)或某些硬件交換信息時(shí)的情況。

本地方法正是這樣一種交流機(jī)制:它為我們提供了一個(gè)非常簡(jiǎn)潔的接口,而且我們無(wú)需去了解 java 應(yīng)用之外的繁瑣的細(xì)節(jié)。

  • 與操作系統(tǒng)交互

JVM 支持著 java 語(yǔ)言本身和運(yùn)行時(shí)庫(kù),它是 java  程序賴以生存的平臺(tái),它由一個(gè)解釋器(解釋字節(jié)碼)和一些連接到本地代碼的庫(kù)組成。然而不管怎樣,它畢竟不是一個(gè)完整的系統(tǒng),它經(jīng)常依賴于一些底層(underneath  在下面的)系統(tǒng)的支持。這些底層系統(tǒng)常常是強(qiáng)大的操作系統(tǒng)。通過使用本地方法,我們得以用 java 實(shí)現(xiàn)了 jre 的與底層系統(tǒng)的交互,甚至 JVM  的一些部分就是用 C 寫的,還有,如果我們要使用一些 java 語(yǔ)言本身沒有提供封裝的操作系統(tǒng)的特性時(shí),我們也需要使用本地方法。

Sun's Java Sun 的解釋器是用 C 實(shí)現(xiàn)的,這使得它能像一些普通的 C 一樣與外部交互。jre 大部分是用java  實(shí)現(xiàn)的,它也通過一些本地方法與外界交互。例如:類 java.lang.Thread

的 setPriority() 方法是用 java 實(shí)現(xiàn)的,但是它實(shí)現(xiàn)調(diào)用的是該類里的本地方法setPriority0()。這個(gè)本地方法是用 C  實(shí)現(xiàn)的,并被植入 JVM 內(nèi)部,在 Windows 95 的平臺(tái)上,這個(gè)本地方法最終將調(diào)用 Win32 SetPriority()  API。這是一個(gè)本地方法的具體實(shí)現(xiàn)由JVM直接提供,更多的情況是本地方法由外部的動(dòng)態(tài)鏈接庫(kù)(external dynamic link  library)提供,然后被 JVM 調(diào)用。

四、Java 堆(Heap)

Java 堆的概念

Java  堆可以說是虛擬機(jī)中最大一塊內(nèi)存了。它是所有線程所共享的內(nèi)存區(qū)域,幾乎所有的實(shí)例對(duì)象都是在這塊區(qū)域中存放。當(dāng)然,隨著JIT編譯器的發(fā)展,所有對(duì)象在堆上分配漸漸變得不那么“絕對(duì)”了。

Java 堆是垃圾收集器管理的主要區(qū)域。由于現(xiàn)在的收集器基本上采用的都是分代收集算法,所有 Java  堆可以細(xì)分為:新生代和老年代。在細(xì)致分就是把新生代分為:

  • Eden 空間

  • From Survivor

  • To Survivor

根據(jù) Java 虛擬機(jī)規(guī)范的規(guī)定:

Java  堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可,就像我們的磁盤空間一樣。在實(shí)現(xiàn)時(shí),既可以實(shí)現(xiàn)成固定大小的,也可以是可擴(kuò)展的,不過當(dāng)前主流的虛擬機(jī)都是按照可擴(kuò)展來(lái)實(shí)現(xiàn)的。

Java 堆的特點(diǎn)

  • 線程間共享區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建

  • 是虛擬機(jī)中最大的一塊內(nèi)存,幾乎所有的實(shí)例對(duì)象都是在這塊區(qū)域中存放

Java 堆的異常

當(dāng)堆無(wú)法再擴(kuò)展時(shí),會(huì)拋出 OutOfMemoryError 異常。

Java 堆的作用

唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在 java 堆中分配內(nèi)存

Java 堆的運(yùn)用

通過 -Xmx 和 -Xms 控制

五、程序計(jì)算器(Program Counter Register)

程序計(jì)算器的概念

類似于 PC 寄存器,程序計(jì)數(shù)器是線程私有的區(qū)域,每個(gè)線程都有自己的程序計(jì)算器。可以把它看成是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。

程序計(jì)算器的特點(diǎn)

  • 線程私有

  • 占用的內(nèi)存空間小

  • 此內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OOM(OutOfMemoryError)情況的區(qū)域

程序計(jì)算器的異常

此內(nèi)存區(qū)域是唯一一個(gè)在 Java 虛擬機(jī)規(guī)范中沒有規(guī)定任何 OOM(OutOfMemoryError)情況的區(qū)域

程序計(jì)算器的作用

  • 信號(hào)指示器:多線程間切換時(shí),需恢復(fù)每一個(gè)線程的當(dāng)前執(zhí)行位置,通過程序計(jì)數(shù)器中的值尋找要執(zhí)行的指令的字節(jié)碼

  • 如果線程在執(zhí)行 Java 方法,計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令地址;如果執(zhí)行的是 Native  方法,計(jì)數(shù)器的值為空(Undefined)。

程序計(jì)算器的運(yùn)用

通過 -Xmx 和 -Xms 控制

六、直接內(nèi)存(Direct Memory)

什么是直接內(nèi)存與非直接內(nèi)存?

根據(jù)官方文檔的描述:

A byte buffer is either direct or non-direct. Given a direct byte buffer, the  Java virtual machine will make a best effort to perform native I/O operations  directly upon it. That is, it will attempt to avoid copying the buffer's content  to (or from) an intermediate buffer before (or after) each invocation of one of  the underlying operating system's native I/O operations.

byte byffer 可以是兩種類型,一種是基于直接內(nèi)存(也就是非堆內(nèi)存);另一種是非直接內(nèi)存(也就是堆內(nèi)存)。

直接內(nèi)存(Direct Memory)既不屬于虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不屬于  Java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域,但是這部分內(nèi)存卻被頻繁地使用,而且還可能導(dǎo)致OutOfMemoryError 異常出現(xiàn)。

對(duì)于直接內(nèi)存來(lái)說,JVM 將會(huì)在 IO 操作上具有更高的性能,因?yàn)樗苯幼饔糜诒镜叵到y(tǒng)的 IO 操作。而堆內(nèi)存如果要作 IO  操作,會(huì)先復(fù)制到直接內(nèi)存,再利用本地 IO 處理。

從數(shù)據(jù)流的角度,非直接內(nèi)存的作用鏈:

本地IO-->直接內(nèi)存-->非直接內(nèi)存-->直接內(nèi)存-->本地IO

而直接內(nèi)存的作用鏈:

本地IO-->直接內(nèi)存-->本地IO

很明顯,在做 IO 處理時(shí),比如網(wǎng)絡(luò)發(fā)送大量數(shù)據(jù)時(shí),直接內(nèi)存會(huì)具有更高的效率。

A direct byte buffer may be created by invoking the allocateDirect factory  method of this class. The buffers returned by this method typically have  somewhat higher allocation and deallocation costs than non-direct buffers. The  contents of direct buffers may reside outside of the normal garbage-collected  heap, and so their impact upon the memory footprint(內(nèi)存占用) of an application  might not be obvious. It is therefore recommended that direct buffers be  allocated primarily for large, long-lived buffers that are subject to the  underlying system's native I/O operations. In general it is best to allocate  direct buffers only when they yield a measureable gain in program  performance.

但是由于直接內(nèi)存使用allocateDirect  創(chuàng)建,它比申請(qǐng)普通的堆內(nèi)存需要耗費(fèi)更高的性能。不過它不會(huì)占用應(yīng)用的堆內(nèi)存。所以,當(dāng)你有大量數(shù)據(jù)要緩存時(shí),并且它的生命周期又比較長(zhǎng),那么使用直接內(nèi)存是個(gè)不錯(cuò)的選擇。但如果該選擇不能帶來(lái)顯著的性能提升,推薦使用堆內(nèi)存。

在 JDK1.4 的 NIO 中,ByteBuffer 有個(gè)方法是:

public static ByteBuffer allocateDirect(int capacity) {  return new DirectByteBuffer(capacity); } DirectByteBuffer(int cap) {  ......  protected static final Unsafe unsafe = Bits.unsafe();  unsafe.allocateMemory(size);  ...... } public final class Unsafe {  ......  public native long allocateMemory(long var1);  ...... }

另外直接內(nèi)受限于本機(jī)總內(nèi)存(包括 RAM 及 SWAP 區(qū)或者分頁(yè)文件)的大小及處理器尋址空間的限制。

服務(wù)器管理員配置虛擬機(jī)參數(shù)時(shí),一般會(huì)根據(jù)實(shí)際內(nèi)存設(shè)置 -Xmx  等參數(shù)信息,但經(jīng)常會(huì)忽略掉直接內(nèi)存,使得各個(gè)內(nèi)存區(qū)域的總和大于物理內(nèi)存限制(包括物理上的和操作系統(tǒng)級(jí)的限制),從而導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn)  OutOfMemoryError 異常。

直接內(nèi)存的特點(diǎn)

  • 不受 Java 堆大小的限制

  • 既不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是 Java 虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域,不會(huì)占用應(yīng)用的內(nèi)存

  • IO 操作上具有更高的性能,因?yàn)樗苯幼饔糜诒镜叵到y(tǒng)的 IO 操作

  • 它比申請(qǐng)普通的堆內(nèi)存需要耗費(fèi)更高的性能。

直接內(nèi)存的異常

動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn) OutOfMemoryError 異常

直接內(nèi)存的作用

基于通道(Channel)與緩沖區(qū)(Buffer)的 I/O 方式,它可以使用 Native 函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過一個(gè)存儲(chǔ)在 Java  堆里面的 DirectByteBuffer 對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽?Java 堆和Native  堆中來(lái)回復(fù)制數(shù)據(jù)。

直接內(nèi)存的運(yùn)用

XX:MaxDirectMemorySize=10M

直接內(nèi)存的使用場(chǎng)景

例如在 IO 處理時(shí),比如網(wǎng)絡(luò)發(fā)送大量數(shù)據(jù)時(shí),直接內(nèi)存會(huì)具有更高的效率。

到此,相信大家對(duì)“怎么理解并掌握J(rèn)ava虛擬機(jī)內(nèi)存區(qū)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI