最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2021年06月07日 09:42:04   作者:月伴飛魚  
內(nèi)存安全問題是每個程序員開發(fā)時都需要面對的問題,本文介紹了JVM管理內(nèi)存的原理以及內(nèi)存安全問題需要注意的地方,有此需求的朋友可以參考下本文

前言

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

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

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

內(nèi)存管理

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

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

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

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

內(nèi)存溢出

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

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

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

堆內(nèi)存溢出

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

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

棧溢出

單個線程下不斷擴(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() {
                @Override
                public void run() {
                    dontStop();
                }
            });
            thread.start();
        }
    }
    public static void main(String[] args) {
        StackOOM stackOOM = new StackOOM();
        stackOOM.stackLeadByThread();
    }
}

運(yùn)行時常量池溢出

不斷的在常量池中新建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)行時產(chǎn)生大量的動態(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() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o, objects);
                }
            });
            enhancer.create();
        }
    }
}

元空間溢出

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

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

直接申請分配內(nèi)存(實(shí)際上并沒有真正向操作系統(tǒ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);
        }
    }
}

常見案例

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

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

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

  • 查詢出大量對象

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

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

這類為外部接口性能較慢,占用內(nèi)存較大,并且短時間內(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插件或一個獨(dú)立軟件使用,MAT是一個高性能、具備豐富功能的Java堆內(nèi)存分析工具,主要用來排查內(nèi)存泄漏和內(nèi)存浪費(fèi)的問題。

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

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

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

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

打開Histogram類實(shí)例表

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

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

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

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

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

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

以上就是Java 內(nèi)存安全問題的注意事項(xiàng)的詳細(xì)內(nèi)容,更多關(guān)于Java 內(nèi)存安全問題的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MyBatis?動態(tài)SQL使用及原理

    MyBatis?動態(tài)SQL使用及原理

    這篇文章主要為大家介紹了MyBatis動態(tài)SQL使用及原理的學(xué)習(xí)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • SpringBoot與knife4j的整合使用過程

    SpringBoot與knife4j的整合使用過程

    Knife4j?是一個基于Swagger構(gòu)建的開源?JavaAPI文檔工具,主要包括兩大核心功能:文檔說明和在線調(diào)試,這篇文章主要介紹了SpringBoot與knife4j的整合使用,需要的朋友可以參考下
    2024-08-08
  • 全面理解java中的構(gòu)造方法以及this關(guān)鍵字的用法

    全面理解java中的構(gòu)造方法以及this關(guān)鍵字的用法

    本篇文章主要概述了如何用構(gòu)造方法初始化對象,this屬性名訪問成員變量方法,和this()的用法,感興趣的小伙伴一起來學(xué)習(xí)吧
    2023-03-03
  • 通過一個命令輕松切換Java的版本

    通過一個命令輕松切換Java的版本

    這篇文章主要給大家介紹了如何通過一個命令輕松實(shí)現(xiàn)切換Java的版本,通過本文介紹的方法,大家就可以將jdk版本之間輕松切換,需要的朋友可以參考學(xué)習(xí),下面跟著小編一起來看看吧。
    2017-05-05
  • 一個applicationContext 加載錯誤導(dǎo)致的阻塞問題及解決方法

    一個applicationContext 加載錯誤導(dǎo)致的阻塞問題及解決方法

    這篇文章主要介紹了一個applicationContext 加載錯誤導(dǎo)致的阻塞問題及解決方法,需要的朋友可以參考下
    2018-11-11
  • Spring boot自定義http反饋狀態(tài)碼詳解

    Spring boot自定義http反饋狀態(tài)碼詳解

    這篇文章主要給大家介紹了Spring boot自定義http反饋狀態(tài)碼的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。
    2017-06-06
  • Java實(shí)現(xiàn)解析第三方接口返回的json

    Java實(shí)現(xiàn)解析第三方接口返回的json

    在實(shí)際開發(fā)過程中,免不了和其他公司進(jìn)行聯(lián)調(diào),調(diào)用第三方接口,這個時候我們就需要根據(jù)對方返回的數(shù)據(jù)進(jìn)行解析,獲得我們想要的字段,下面我們就來看看具體有哪些方法吧
    2024-01-01
  • 淺析java中密文的創(chuàng)建和校驗(yàn)

    淺析java中密文的創(chuàng)建和校驗(yàn)

    這篇文章主要為大家詳細(xì)介紹了java中密文的創(chuàng)建和校驗(yàn)的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • 深入了解Java中Synchronized關(guān)鍵字的實(shí)現(xiàn)原理

    深入了解Java中Synchronized關(guān)鍵字的實(shí)現(xiàn)原理

    synchronized是JVM的內(nèi)置鎖,基于Monitor機(jī)制實(shí)現(xiàn),每一個對象都有一個與之關(guān)聯(lián)的監(jiān)視器?(Monitor),這個監(jiān)視器充當(dāng)了一種互斥鎖的角色,本文就詳細(xì)聊一聊Synchronized關(guān)鍵字的實(shí)現(xiàn)原理,需要的朋友可以參考下
    2023-06-06
  • Java工具類之@RequestMapping注解

    Java工具類之@RequestMapping注解

    今天帶大家來學(xué)習(xí)Java工具類,文中對注解@RequestMapping作了非常詳細(xì)的介紹,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05

最新評論

罗甸县| 光山县| 新兴县| 巴东县| 老河口市| 乐昌市| 仁布县| 昭平县| 肥城市| 云梦县| 清镇市| 鹿邑县| 双城市| 邹城市| 苍南县| 农安县| 登封市| 秦安县| 蒙自县| 郎溪县| 广州市| 社旗县| 杭锦旗| 那曲县| 石景山区| 五台县| 上杭县| 太仆寺旗| 邓州市| 历史| 平远县| 库伦旗| 太康县| 铁岭市| 贺兰县| 镇远县| 正阳县| 山丹县| 延边| 德保县| 乐东|