电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

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

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

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

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

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

內(nèi)存管理

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

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

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

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

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

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

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

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

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

堆內(nèi)存溢出

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

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

單個(gè)線程下不斷擴(kuò)大棧的深度引起棧溢出。

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)建線程,達(dá)到最大棧容量。

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(); }}運(yùn)行時(shí)常量池溢出

不斷的在常量池中新建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é)碼運(yùn)行時(shí)產(chǎn)生大量的動(dòng)態(tài)類,最終撐爆內(nèi)存導(dǎo)致方法區(qū)溢出。

public class MethodAreaOOM { static class ObjectInMethod { } public static void main(final String[] args) {// 借助CGLib實(shí)現(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運(yùn)行時(shí)產(chǎn)生大量動(dòng)態(tài)類,唯一的區(qū)別在于運(yùn)行環(huán)境修改為Java 1.8,設(shè)置-XX:MaxMetaspaceSize參數(shù),便可以收獲java.lang.OutOfMemoryError: Metaspace這一報(bào)錯(cuò)

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

直接申請(qǐng)分配內(nèi)存(實(shí)際上并沒有真正向操作系統(tǒng)申請(qǐng)分配內(nèi)存,而是通過計(jì)算得知內(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);} }}常見案例

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

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

因?yàn)閭鬏敂?shù)量過大、或一些極端情況導(dǎo)致代碼中間結(jié)果對(duì)象數(shù)據(jù)量過大,過大的數(shù)據(jù)量撐爆內(nèi)存

查詢出大量對(duì)象

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

接口性能問題導(dǎo)致

這類為外部接口性能較慢,占用內(nèi)存較大,并且短時(shí)間內(nèi)高QPS導(dǎo)致的,導(dǎo)致服務(wù)內(nèi)存不足,線程堆積或掛起進(jìn)而出現(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插件或一個(gè)獨(dú)立軟件使用,MAT是一個(gè)高性能、具備豐富功能的Java堆內(nèi)存分析工具,主要用來排查內(nèi)存泄漏和內(nèi)存浪費(fèi)的問題。

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

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

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

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

以運(yùn)行時(shí)常量池溢出為例

打開Histogram類實(shí)例表

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

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

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

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

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

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

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

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

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

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 盘古网络技术有限公司| 高光谱相机-近红外高光谱相机厂家-高光谱成像仪-SINESPEC 赛斯拜克 | 吊篮式|移动式冷热冲击试验箱-二槽冷热冲击试验箱-广东科宝 | 微水泥_硅藻泥_艺术涂料_艺术漆_艺术漆加盟-青岛泥之韵环保壁材 武汉EPS线条_EPS装饰线条_EPS构件_湖北博欧EPS线条厂家 | 二手Sciex液质联用仪-岛津气质联用仪-二手安捷伦气质联用仪-上海隐智科学仪器有限公司 | 北京中航时代-耐电压击穿试验仪厂家-电压击穿试验机 | 黄石东方妇产医院_黄石妇科医院哪家好_黄石无痛人流医院 | 风电变桨伺服驱动器-风电偏航变桨系统-深圳众城卓越科技有限公司 | 温室大棚建设|水肥一体化|物联网系统 | 高压管道冲洗清洗机_液压剪叉式升降机平台厂家-林君机电 | 深圳高新投三江工业消防解决方案提供厂家_服务商_园区智慧消防_储能消防解决方案服务商_高新投三江 | 雨燕360体育免费直播_雨燕360免费NBA直播_NBA篮球高清直播无插件-雨燕360体育直播 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 开云(中国)Kaiyun·官方网站 - 登录入口 | 乙炔气体报警装置|固定式氯化氢检测仪|河南驰诚电气百科 | 精密模具-双色注塑模具加工-深圳铭洋宇通 | 立式矫直机_卧式矫直机-无锡金矫机械制造有限公司 | 铝箔袋,铝箔袋厂家,东莞铝箔袋,防静电铝箔袋,防静电屏蔽袋,防静电真空袋,真空袋-东莞铭晋让您的产品与众不同 | 自动部分收集器,进口无油隔膜真空泵,SPME固相微萃取头-上海楚定分析仪器有限公司 | 贴板式电磁阀-不锈钢-气动上展式放料阀-上海弗雷西阀门有限公司 工业机械三维动画制作 环保设备原理三维演示动画 自动化装配产线三维动画制作公司-南京燃动数字 | 篷房|仓储篷房|铝合金篷房|体育篷房|篷房厂家-华烨建筑科技官网 知名电动蝶阀,电动球阀,气动蝶阀,气动球阀生产厂家|价格透明-【固菲阀门官网】 | 武汉印刷厂-不干胶标签印刷厂-武汉不干胶印刷-武汉标签印刷厂-武汉标签制作 - 善进特种标签印刷厂 | 直流大电流电源,燃料电池检漏设备-上海政飞 | 微型气象仪_气象传感器_防爆气象传感器-天合传感器大全 | 大型工业风扇_工业大风扇_大吊扇_厂房车间降温-合昌大风扇 | 钢丝绳探伤仪-钢丝绳检测仪-钢丝绳探伤设备-洛阳泰斯特探伤技术有限公司 | 刹车盘机床-刹车盘生产线-龙口亨嘉智能装备 | 自动焊锡机_点胶机_螺丝机-锐驰机器人 | 印刷人才网 印刷、包装、造纸,中国80%的印刷企业人才招聘选印刷人才网! | 包头市鑫枫装饰有限公司| 软启动器-上海能曼电气有限公司 真空搅拌机-行星搅拌机-双行星动力混合机-广州市番禺区源创化工设备厂 | 西宁装修_西宁装修公司-西宁业之峰装饰-青海业之峰墅级装饰设计公司【官网】 | 小型气象站_便携式自动气象站_校园气象站-竞道气象设备网 | 蜘蛛车-高空作业平台-升降机-高空作业车租赁-臂式伸缩臂叉装车-登高车出租厂家 - 普雷斯特机械设备(北京)有限公司 | 英思科GTD-3000EX(美国英思科气体检测仪MX4MX6)百科-北京嘉华众信科技有限公司 | 海外整合营销-独立站营销-社交媒体运营_广州甲壳虫跨境网络服务 焊管生产线_焊管机组_轧辊模具_焊管设备_焊管设备厂家_石家庄翔昱机械 | 防爆电机_防爆电机型号_河南省南洋防爆电机有限公司 | 智能化的检漏仪_气密性测试仪_流量测试仪_流阻阻力测试仪_呼吸管快速检漏仪_连接器防水测试仪_车载镜头测试仪_奥图自动化科技 | 熔体泵|换网器|熔体齿轮泵|熔体计量泵厂家-郑州巴特熔体泵有限公司 | 护腰带生产厂家_磁石_医用_热压护腰_登山护膝_背姿矫正带_保健护具_医疗护具-衡水港盛 | 全自动包装秤_全自动上袋机_全自动套袋机_高位码垛机_全自动包装码垛系统生产线-三维汉界机器(山东)股份有限公司 |