java sof栈泄露_Java內存溢出與棧溢出

本文介绍了Java内存管理的背景知识,包括JVM的内存区域划分,如堆和栈。详细讨论了堆溢出和栈溢出的情况,包括内存泄漏和内存分配过大导致的溢出问题,并提供了示例代码来展示这两种情况。同时,解释了栈溢出错误`StackOverflowError`的产生原因和示例。
摘要由CSDN通过智能技术生成

一、背景知識

1、JVM體系結構

52d2e0f8c1add53a0495098fdb9625cf.png

2、JVM運行時數據區

01d60dd44e7bc97190b870929fcd4d82.png

3、JVM內存模型

JVM運行時內存 = 共享內存區 + 線程內存區

566e779dfec36282590fe0f90a4b89db.png

3-1、共享內存區

共享內存區 = 持久帶 + 堆

持久帶 = 方法區 + 其他

堆 = Old Space + Young Space

Young Space = Eden + S0 + S1

62779b574888e7dbff5b30fc8ee1c868.png

3-1-1、持久代

JVM用持久帶(Permanent Space)實現方法區,主要存放所有已加載的類信息,方法信息,常量池等等。

可通過-XX:PermSize和-XX:MaxPermSize來指定持久帶初始化值和最大值。

Permanent Space並不等同於方法區,只不過是Hotspot JVM用Permanent Space來實現方法區而已,有些虛擬機沒

有Permanent Space而用其他機制來實現方法區。

3-1-2、堆

堆(heap),主要用來存放類的對象實例信息(包括new操作實例化的對象和定義的數組)。

堆分為Old Space(又名,Tenured Generation)和Young Space。

Old Space主要存放應用程序中生命周期長的存活對象;

Eden(伊甸園)主要存放新生的對象;

S0和S1是兩個大小相同的內存區域,主要存放每次垃圾回收后Eden存活的對象,作為對象從Eden過渡到Old Space

的緩沖地帶(S是指英文單詞Survivor Space)。

堆之所以要划分區間,是為了方便對象創建和垃圾回收,后面垃圾回收部分會解釋。

3-2、線程內存區

線程內存區=單個線程內存+單個線程內存+.......

單個線程內存=PC Regster+JVM棧+本地方法棧

JVM棧=棧幀+棧幀+.....

棧幀=局域變量區+操作數區+幀數據區

261c0ed3f1cbbbe9f7c37f922b7febf7.png

在Java中,一個線程會對應一個JVM棧(JVM Stack),JVM棧里記錄了線程的運行狀態。

JVM棧以棧幀為單位組成,一個棧幀代表一個方法調用。棧幀由三部分組成:局部變量區、操作數棧、幀數據區。

二、堆溢出

堆(Heap)是Java存放對象實例的地方。

堆溢出可以分為以下兩種情況,這兩種情況都會拋出OutOfMemoryError:java heap space異常:

1、內存泄漏

內存泄漏是指對象實例在新建和使用完畢后,仍然被引用,沒能被垃圾回收釋放,一直積累,直到沒有剩余

內存可用。

如果內存泄露,我們要找出泄露的對象是怎么被GC ROOT引用起來,然后通過引用鏈來具體分析泄露的原因。

分析內存泄漏的工具有:Jprofiler,visualvm等。

示例代碼:

package com.jvm;

import java.util.ArrayList;

import java.util.List;

import java.util.UUID;

/**

* 內存泄漏

* @author feizi

* @time 2015-1-23上午8:42:53

*/

public class OOMTest {

public static void main(String[] args) {

List list = new ArrayList();

while(true){

list.add(UUID.randomUUID());

}

}

}

看看控制台的輸出結果,因為我這邊的JVM設置的參數內存足夠大,所以需要等待一定的時間,才能看到效果:

d13666e80c76e626551a048e2650c6da.png

如果是用CMD命令行,就可以自己指定參數編譯運行了,這樣效果就更快一些:

通過下列命令運行程序,注意先要用javac命令將.java源文件編譯成.class類字節碼文件。

java -Xms10M -Xmx10M -XX:-UseGCOverheadLimit OOMTest

1af3e2ff54efedf7f3720c94240b6a99.png

2、內存溢出

內存溢出是指當我們新建一個實力對象時,實例對象所需占用的內存空間大於堆的可用空間。

如果出現了內存溢出問題,這往往是程序本生需要的內存大於了我們給虛擬機配置的內存,這種情況下,我們可以采用調大-Xmx來解決這種問題。

示例代碼:

package com.jvm;

import java.util.ArrayList;

import java.util.List;

/**

* 內存溢出

* @author feizi

* @time 2015-1-23上午8:56:22

*/

public class OOMTest_1 {

public static void main(String args[]){

List byteList = new ArrayList();

byteList.add(new byte[1000 * 1024 * 1024]);

}

}

看看控制台的運行效果:

21fb29c3c8b17f52cc6dd18d0e218952.png

使用CMD命令行指定參數運行:

java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest_1

19cd40d585aa46073cf1be495d1f33b8.png

三、線程棧

棧(JVM Stack)存放主要是棧幀( 局部變量表, 操作數棧 , 動態鏈接 , 方法出口信息 )的地方。注意區分棧和棧幀:棧里包含棧幀。與線程棧相關的內存異常有兩個:a)、StackOverflowError(方法調用層次太深,內存不夠新建棧幀)

b)、OutOfMemoryError(線程太多,內存不夠新建線程)

1、java.lang.StackOverflowError

棧溢出拋出java.lang.StackOverflowError錯誤,出現此種情況是因為方法運行的時候,請求新建棧幀時,

棧所剩空間小於戰幀所需空間。

例如,通過遞歸調用方法,不停的產生棧幀,一直把棧空間堆滿,直到拋出異常 :

示例代碼:

package com.jvm;

/**

* 棧溢出

* @author feizi

* @time 2015-1-23上午9:13:11

*/

public class SOFTest {

public void stackOverFlowMethod(){

stackOverFlowMethod();

}

/**

* 通過遞歸調用方法,不停的產生棧幀,一直把棧空間堆滿,直到拋出異常 :

* @param args

*/

public static void main(String[] args) {

SOFTest sof = new SOFTest();

sof.stackOverFlowMethod();

}

}

看看控制台運行的效果:

b4a0ac0b0a723c51496ba23bf875d003.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值