国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

Java 內(nèi)存安全問題的注意事項

瀏覽:81日期:2022-08-11 09:45:54
目錄前言內(nèi)存管理Java各版本內(nèi)存管理改進內(nèi)存溢出堆內(nèi)存溢出棧溢出運行時常量池溢出方法區(qū)溢出元空間溢出本機直接內(nèi)存溢出常見案例問題排查前言

Java在內(nèi)存管理方面是要比C/C++更方便的,不需要為每一個對象編寫釋放內(nèi)存的代碼,JVM虛擬機將為我們選擇合適的時間釋放內(nèi)存空間,使得程序不容易出現(xiàn)內(nèi)存泄漏和溢出的問題

不過,也正是因為Java把內(nèi)存控制的權(quán)利交給了Java虛擬機,一旦出現(xiàn)內(nèi)存泄漏和溢出方面的問題,如果不了解虛擬機是怎么使用內(nèi)存的,那排查錯誤將會成為一項異常艱難的工作

下面先看看JVM如何管理內(nèi)存的

內(nèi)存管理

根據(jù)Java虛擬機規(guī)范(第3版) 的規(guī)定,Java虛擬機所管理的內(nèi)存將會包括以下幾個運行內(nèi)存數(shù)據(jù)區(qū)域:

線程隔離數(shù)據(jù)區(qū): 程序計數(shù)器: 當前線程所執(zhí)行字節(jié)碼的行號指示器虛擬機棧: 里面的元素叫棧幀,存儲局部變量表、操作棧、動態(tài)鏈接、方法出口等,方法被調(diào)用到執(zhí)行完成的過程對應(yīng)一個棧幀在虛擬機棧中入棧到出棧的過程。本地方法棧: 和虛擬機棧的區(qū)別在于虛擬機棧為虛擬機執(zhí)行Java方法,本地方法棧為虛擬機使用到的本地Native方法服務(wù)。 線程共享數(shù)據(jù)區(qū): 方法區(qū): 可以描述為堆的一個邏輯部分,或者說使用永久代來實現(xiàn)方法區(qū)。存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。堆: 唯一目的就是存放對象的實例,是垃圾回收管理器的主要區(qū)域,分為Eden、From/To Survivor空間。

Java 內(nèi)存安全問題的注意事項

Java各版本內(nèi)存管理改進

下圖中永久代理解為堆的邏輯區(qū)域,移除永久代的工作從JDK7就已經(jīng)開始了,部分永久代中的數(shù)據(jù)(常量池)在JDK7中就已經(jīng)轉(zhuǎn)移到了堆中,JDK8中直接去除了永久代,方法區(qū)中的數(shù)據(jù)大部分被移到堆里面,還剩下一些元數(shù)據(jù)被保存在元空間里

Java 內(nèi)存安全問題的注意事項

內(nèi)存溢出 內(nèi)存泄露Memory Leak: 申請的內(nèi)存空間沒有及時釋放,導致后續(xù)程序里這塊內(nèi)容永遠被占用。 內(nèi)存溢出Out Of Memory: 要求的內(nèi)存超過了系統(tǒng)所能提供的

運行時數(shù)據(jù)區(qū)域的常見異常

在JVM中,除了程序計數(shù)器外,虛擬機內(nèi)存的其他幾個運行時數(shù)據(jù)區(qū)域都有發(fā)生OOM異常的可能。

堆內(nèi)存溢出

不斷的創(chuàng)建對象,并且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象。

public class HeapOOM { static class ObjectInHeap{ } public static void main(String[] args) {List<ObjectInHeap> list = new ArrayList();while (true) { list.add(new ObjectInHeap());} }}棧溢出

單個線程下不斷擴大棧的深度引起棧溢出。

public class StackSOF { private int stackLength = 1; public void stackLeak() {stackLength++;stackLeak(); } public static void main(String[] args) {StackSOF sof = new StackSOF();try { sof.stackLeak();} catch (Throwable e) { System.out.println('Stack Length: ' + sof.stackLength); throw e;} }}

循環(huán)的創(chuàng)建線程,達到最大棧容量。

public class StackOOM { private void dontStop() {while (true) {} } public void stackLeadByThread() {while (true) { Thread thread = new Thread(new Runnable() {@Overridepublic void run() { dontStop();} }); thread.start();} } public static void main(String[] args) {StackOOM stackOOM = new StackOOM();stackOOM.stackLeadByThread(); }}運行時常量池溢出

不斷的在常量池中新建String,并且保持引用不釋放。

public class RuntimeConstantPoolOOM { public static void main(String[] args) {// 使用List保持著常量池的引用,避免Full GC回收常量池List<String> list = new ArrayList<String>();int i = 0;while (true) { // intern()方法使String放入常量池 list.add(String.valueOf(i++).intern());} }}方法區(qū)溢出

借助CGLib直接操作字節(jié)碼運行時產(chǎn)生大量的動態(tài)類,最終撐爆內(nèi)存導致方法區(qū)溢出。

public class MethodAreaOOM { static class ObjectInMethod { } public static void main(final String[] args) {// 借助CGLib實現(xiàn)while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(ObjectInMethod.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o, objects);} }); enhancer.create();} }}元空間溢出

助CG Lib運行時產(chǎn)生大量動態(tài)類,唯一的區(qū)別在于運行環(huán)境修改為Java 1.8,設(shè)置-XX:MaxMetaspaceSize參數(shù),便可以收獲java.lang.OutOfMemoryError: Metaspace這一報錯

本機直接內(nèi)存溢出

直接申請分配內(nèi)存(實際上并沒有真正向操作系統(tǒng)申請分配內(nèi)存,而是通過計算得知內(nèi)存無法分配,于是拋出異常)

public class DirectMemoryOOM { private static final int _1MB = 1024 * 1024; public static void main(String[] args) throws IllegalAccessException {Field unsafeField = Unsafe.class.getDeclaredFields()[0];unsafeField.setAccessible(true);Unsafe unsafe = (Unsafe) unsafeField.get(null);while (true) { unsafe.allocateMemory(_1MB);} }}常見案例

在工作中一般會遇到有以下幾種情況導致內(nèi)存問題

傳輸數(shù)據(jù)量過大

因為傳輸數(shù)量過大、或一些極端情況導致代碼中間結(jié)果對象數(shù)據(jù)量過大,過大的數(shù)據(jù)量撐爆內(nèi)存

查詢出大量對象

這個多為SQL語句設(shè)置問題,SQL未設(shè)置分頁,用戶一次查詢數(shù)據(jù)量過大、頻繁查詢SQL導致內(nèi)存堆積、或是未作判空處理導致WHERE條件為空查詢出超大數(shù)據(jù)量等

接口性能問題導致

這類為外部接口性能較慢,占用內(nèi)存較大,并且短時間內(nèi)高QPS導致的,導致服務(wù)內(nèi)存不足,線程堆積或掛起進而出現(xiàn)FullGC

元空間問題

使用了大量的反射代碼,Java字節(jié)碼存取器生成的類不斷生成

問題排查

使用jmap分析內(nèi)存泄漏

1.生成dump文件

jmap -dump:format=b,file=/xx/xx/xx.hprof pid

2.dump文件下載到本地

3.dump文件分析

可以使用MAT,MAT可作為Eclipse插件或一個獨立軟件使用,MAT是一個高性能、具備豐富功能的Java堆內(nèi)存分析工具,主要用來排查內(nèi)存泄漏和內(nèi)存浪費的問題。

使用MAT打開上一部后綴名.hprof的dump文件

Java 內(nèi)存安全問題的注意事項

Histogram:直方圖,各個類的實例,包括個數(shù)和大小,可以查看類引用和被引用的路徑。 Dominator Tree:支配圖,列出所有線程和線程下面的那些對象占用的空間。 Top Consumers:通過圖形列出消耗內(nèi)存多的實例。 Leak Suspects:MAT自動分析的內(nèi)存泄漏報表

可以用這個工具分析出什么對象什么線程占用內(nèi)存空間較大,對象是被什么引用的,線程內(nèi)有哪些資源占用很高

以運行時常量池溢出為例

打開Histogram類實例表

Objects是類的對象的數(shù)量;Shallow是對象本身占用內(nèi)存大小、不包含其他引用;

Retained是對象自己的Shallow加上直接或間接訪問到對象的Shallow之和,也可以說是GC之后可以回收的內(nèi)存總和

從圖中可以看出運行時常量池溢出的情況,產(chǎn)生了大量的String和char[]實例

Java 內(nèi)存安全問題的注意事項

在char[]上右鍵可以得到上圖所有char[]對象的被引用路徑,可以看出這些char數(shù)組都是以String的形式存在ArrayList中,并且是由main這個線程運行的

可以看出是main線程中新建了一個數(shù)組,其中存了32w+個長度為6的char數(shù)組組成的String造成的內(nèi)存溢出

Java 內(nèi)存安全問題的注意事項

關(guān)于MAT的詳細使用可以從MAT官方教程學習更多

以上就是Java 內(nèi)存安全問題的注意事項的詳細內(nèi)容,更多關(guān)于Java 內(nèi)存安全問題的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: Java
相關(guān)文章:
主站蜘蛛池模板: 日韩亚洲天堂 | 久草欧美 | 三级黄色片网站 | 欧美亚洲在线观看 | 日韩欧美中文字幕在线播放 | 国产在线观看一区二区三区四区 | 欧美一级毛片俄罗斯 | 亚洲精品国产专区91在线 | 久久久久久毛片免费播放 | 亚洲第一成年网站大全亚洲 | 亚洲图片在线视频 | 自拍视频区 | 中文字幕亚洲一区二区v@在线 | 亚洲日本va | 日韩欧国产精品一区综合无码 | 综合久久久久久中文字幕 | 国产免费一区二区三区免费视频 | 亚洲国产精品网站久久 | 国产成人精品日本亚洲语音1 | 亚洲国产精久久久久久久春色 | 黄色福利网 | 欧美在线 | 欧美 | 在线亚洲成人 | 高清黄色毛片 | 国产亚洲精品美女一区二区 | 中国a级黄色片 | 国产精亚洲视频 | 中国成人免费视频 | 中国成人在线视频 | 欧美日韩精品一区二区三区 | 成人欧美午夜视频毛片 | 美女视频免费看视频网站 | 99性视频| 日本又黄又爽又免费 | 免费观看一级成人毛片软件 | 一本三道a无线码一区v小说 | 欧美精品在线免费观看 | 亚洲在线免费 | 在线私拍国产福利精品 | 一级片 mp4| 欧美精品一区二区三区视频 |