pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

Java“為"語句實現防止垃圾收集

Java quot;forquot; statement implementation prevents garbage collecting(Java“為語句實現防止垃圾收集)
本文介紹了Java“為"語句實現防止垃圾收集的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

UPD 21.11.2017:該錯誤已在 JDK 中修復,請參閱 Vicente Romero 的評論

UPD 21.11.2017: the bug is fixed in JDK, see comment from Vicente Romero

總結:

如果 for 語句用于任何 Iterable 實現,則集合將保留在堆內存中,直到當前范圍(方法、語句體)結束,并且即使您沒有對集合的任何其他引用并且應用程序需要分配新內存,也不會被垃圾回收.

If for statement is used for any Iterable implementation the collection will remain in the heap memory till the end of current scope (method, statement body) and won't be garbage collected even if you don't have any other references to the collection and the application needs to allocate a new memory.

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8175883

https://bugs.openjdk.java.net/browse/JDK-8175883

例子:

如果我有下一個代碼,它會分配一個包含隨機內容的大字符串列表:

If i have the next code, which allocates a list of large strings with random content:

import java.util.ArrayList;
public class IteratorAndGc {
    
    // number of strings and the size of every string
    static final int N = 7500;

    public static void main(String[] args) {
        System.gc();

        gcInMethod();

        System.gc();
        showMemoryUsage("GC after the method body");

        ArrayList<String> strings2 = generateLargeStringsArray(N);
        showMemoryUsage("Third allocation outside the method is always successful");
    }

    // main testable method
    public static void gcInMethod() {

        showMemoryUsage("Before first memory allocating");
        ArrayList<String> strings = generateLargeStringsArray(N);
        showMemoryUsage("After first memory allocation");


        // this is only one difference - after the iterator created, memory won't be collected till end of this function
        for (String string : strings);
        showMemoryUsage("After iteration");

        strings = null; // discard the reference to the array

        // one says this doesn't guarantee garbage collection,
        // Oracle says "the Java Virtual Machine has made a best effort to reclaim space from all discarded objects".
        // but no matter - the program behavior remains the same with or without this line. You may skip it and test.
        System.gc();

        showMemoryUsage("After force GC in the method body");

        try {
            System.out.println("Try to allocate memory in the method body again:");
            ArrayList<String> strings2 = generateLargeStringsArray(N);
            showMemoryUsage("After secondary memory allocation");
        } catch (OutOfMemoryError e) {
            showMemoryUsage("!!!! Out of memory error !!!!");
            System.out.println();
        }
    }
    
    // function to allocate and return a reference to a lot of memory
    private static ArrayList<String> generateLargeStringsArray(int N) {
        ArrayList<String> strings = new ArrayList<>(N);
        for (int i = 0; i < N; i++) {
            StringBuilder sb = new StringBuilder(N);
            for (int j = 0; j < N; j++) {
                sb.append((char)Math.round(Math.random() * 0xFFFF));
            }
            strings.add(sb.toString());
        }

        return strings;
    }

    // helper method to display current memory status
    public static void showMemoryUsage(String action) {
        long free = Runtime.getRuntime().freeMemory();
        long total = Runtime.getRuntime().totalMemory();
        long max = Runtime.getRuntime().maxMemory();
        long used = total - free;
        System.out.printf("	%40s: %10dk of max %10dk%n", action, used / 1024, max / 1024);
    }
}

有限的內存編譯和運行它,像這樣(180mb):

compile and run it with limited memory, like this (180mb):

javac IteratorAndGc.java   &&   java -Xms180m -Xmx180m IteratorAndGc

在運行時我有:

在第一次分配內存之前:1251k of max 176640k

Before first memory allocating: 1251k of max 176640k

第一次內存分配后:131426k of max 176640k

After first memory allocation: 131426k of max 176640k

迭代后:131426k of max 176640k

After iteration: 131426k of max 176640k

在方法體中強制 GC 后:最大 176640k 的 110682k(幾乎沒有收集到)

After force GC in the method body: 110682k of max 176640k (almost nothing collected)

再次嘗試在方法體中分配內存:

Try to allocate memory in the method body again:

     !!!! Out of memory error !!!!:     168948k of max     176640k

方法體后的GC:459k of max 176640k(垃圾被收集了!)

GC after the method body: 459k of max 176640k (the garbage is collected!)

方法外第三次分配總是成功:117740k of max 163840k

Third allocation outside the method is always successful: 117740k of max 163840k

所以,在 gcInMethod() 內部,我嘗試分配列表,對其進行迭代,丟棄對列表的引用,(可選)強制垃圾收集并再次分配類似的列表.但由于內存不足,我無法分配第二個數組.

So, inside gcInMethod() i tried to allocate the list, iterate over it, discard the reference to the list, (optional)force garbage collection and allocate similar list again. But i can't allocate second array because of lack of memory.

同時,在函數體之外,我可以成功強制垃圾回收(可選)并再次分配相同的數組大小!

In the same time, outside the function body i can successfully force garbage collection (optional) and allocate the same array size again!

為了避免函數體內出現這種 OutOfMemoryError,只需刪除/注釋這一行即可:

To avoid this OutOfMemoryError inside the function body it's enough to remove/comment only this one line:

for (String string : strings); <--這是邪惡的!??!

for (String string : strings); <-- this is the evil!!!

然后輸出如下:

在第一次分配內存之前:1251k of max 176640k

Before first memory allocating: 1251k of max 176640k

第一次內存分配后:最大 176640k 中的 131409k

After first memory allocation: 131409k of max 176640k

迭代后:131409k of max 176640k

After iteration: 131409k of max 176640k

在方法體中強制GC后:497k of max 176640k(垃圾被收集了!)

After force GC in the method body: 497k of max 176640k (the garbage is collected!)

再次嘗試在方法體中分配內存:

Try to allocate memory in the method body again:

二級內存分配后:115541k of max 163840k

After secondary memory allocation: 115541k of max 163840k

方法體后的GC:493k of max 163840k(垃圾被收集了!)

GC after the method body: 493k of max 163840k (the garbage is collected!)

方法外第三次分配總是成功:121300k of max 163840k

Third allocation outside the method is always successful: 121300k of max 163840k

所以,在沒有for迭代的情況下,在丟棄對字符串的引用后成功收集垃圾,并第二次分配(在函數體內)和第三次分配(在方法外).

So, without for iterating the garbage successfully collected after discarding the reference to the strings, and allocated second time (inside the function body) and allocated third time (outside the method).

我的假設:

for 語法構造被編譯成

Iterator iter = strings.iterator();
while(iter.hasNext()){
    iter.next()
}

(我檢查了這個反編譯 javap -c IteratorAndGc.class)

(and i checked this decompiling javap -c IteratorAndGc.class)

并且看起來這個 iter 引用一直停留在范圍內.您無權訪問引用以使其無效,并且 GC 無法執行收集.

And looks like this iter reference stays in the scope till the end. You don't have access to the reference to nullify it, and GC can't perform the collection.

也許這是正常行為(甚至可能在 javac 中指定,但我還沒有找到),但恕我直言,如果編譯器創建了一些實例,它應該關心在之后從范圍中丟棄它們使用.

Maybe this is normal behavior (maybe even specified in javac, but i haven't found), but IMHO if compiler creates some instances it should care about discarding them from the scope after using.

這就是我期望實現 for 語句的方式:

That's how i expect to have the implementation of for statement:

Iterator iter = strings.iterator();
while(iter.hasNext()){
    iter.next()
}
iter = null; // <--- flush the water!

使用的 java 編譯器和運行時版本:

Used java compiler and runtime versions:

javac 1.8.0_111

java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

注意:

  • 問題不在于編程風格、最佳實踐、約定等等,問題是關于Java的效率平臺.

  • the question is not about programming style, best practices, conventions and so on, the question is about an efficiency of Java platform.

問題不在于 System.gc() 行為(您可以刪除所有gc 示例中的調用) - 在第二次字符串分配期間,JVM 必須 釋放丟棄的內存.

the question is not about System.gc() behavior (you may remove all gc calls from the example) - during the second strings allocation the JVM must release the dicarded memory.

對測試java類的引用, 在線編譯器測試(但是這個資源只有50Mb的堆,所以使用N = 5000)

Reference to the test java class, Online compiler to test (but this resource has only 50 Mb of heap, so use N = 5000)

推薦答案

感謝您的錯誤報告.我們已修復此錯誤,請參閱 JDK-8175883.正如這里在 enhanced for 的情況下所評論的,javac 正在生成合成變量,因此對于如下代碼:

Thanks for the bug report. We have fixed this bug, see JDK-8175883. As commented here in the case of the enhanced for, javac was generating synthetic variables so for a code like:

void foo(String[] data) {
    for (String s : data);
}

javac 大約在生成:

javac was approximately generating:

for (String[] arr$ = data, len$ = arr$.length, i$ = 0; i$ < len$; ++i$) {
    String s = arr$[i$];
}

如上所述,這種轉換方法意味著合成變量 arr$ 持有對數組 data 的引用,一旦未引用該數組,就會阻止 GC 收集該數組不再在方法內部.此錯誤已通過生成此代碼修復:

as mentioned above this translation approach implies that the synthetic variable arr$ holds a reference to the array data that impedes the GC to collect the array once it is not referred anymore inside the method. This bug has been fixed by generating this code:

String[] arr$ = data;
String s;
for (int len$ = arr$.length, i$ = 0; i$ < len$; ++i$) {
    s = arr$[i$];
}
arr$ = null;
s = null;

這個想法是將 javac 創建的任何引用類型的合成變量設置為 null 以轉換循環.如果我們談論的是原始類型的數組,那么最后一個對 null 的賦值不是由編譯器生成的.該錯誤已在 repo JDK repo

The idea is to set to null any synthetic variable of a reference type created by javac to translate the loop. If we were talking about an array of a primitive type, then the last assignment to null is not generated by the compiler. The bug has been fixed in repo JDK repo

這篇關于Java“為"語句實現防止垃圾收集的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!

相關文檔推薦

Java Remove Duplicates from an Array?(Java從數組中刪除重復項?)
How to fix Invocation failed Unexpected Response from Server: Unauthorized in Android studio(如何修復調用失敗來自服務器的意外響應:在 Android 工作室中未經授權)
AES encryption, got extra trash characters in decrypted file(AES 加密,解密文件中有多余的垃圾字符)
AES Error: Given final block not properly padded(AES 錯誤:給定的最終塊未正確填充)
Detecting incorrect key using AES/GCM in JAVA(在 JAVA 中使用 AES/GCM 檢測不正確的密鑰)
AES-256-CBC in Java(Java 中的 AES-256-CBC)
主站蜘蛛池模板: 衡阳耐适防护科技有限公司——威仕盾焊接防护用品官网/焊工手套/焊接防护服/皮革防护手套 | 服务器之家 - 专注于服务器技术及软件下载分享 | 真空粉体取样阀,电动楔式闸阀,电动针型阀-耐苛尔(上海)自动化仪表有限公司 | 耐酸碱胶管_耐腐蚀软管总成_化学品输送软管_漯河利通液压科技耐油耐磨喷砂软管|耐腐蚀化学软管 | 解放卡车|出口|济南重汽|报价大全|山东三维商贸有限公司 | 空冷器|空气冷却器|空水冷却器-无锡赛迪森机械有限公司[官网] | 等离子空气净化器_医用空气消毒机_空气净化消毒机_中央家用新风系统厂家_利安达官网 | SF6环境监测系统-接地环流在线监测装置-瑟恩实业 | 锡膏喷印机-全自动涂覆机厂家-全自动点胶机-视觉点胶机-深圳市博明智控科技有限公司 | 右手官网|右手工业设计|外观设计公司|工业设计公司|产品创新设计|医疗产品结构设计|EMC产品结构设计 | 报警器_家用防盗报警器_烟雾报警器_燃气报警器_防盗报警系统厂家-深圳市刻锐智能科技有限公司 | uv机-uv灯-uvled光固化机-生产厂家-蓝盾机电 | 超声波_清洗机_超声波清洗机专业生产厂家-深圳市好顺超声设备有限公司 | Eiafans.com_环评爱好者 环评网|环评论坛|环评报告公示网|竣工环保验收公示网|环保验收报告公示网|环保自主验收公示|环评公示网|环保公示网|注册环评工程师|环境影响评价|环评师|规划环评|环评报告|环评考试网|环评论坛 - Powered by Discuz! | 体感VRAR全息沉浸式3D投影多媒体展厅展会游戏互动-万展互动 | 定制防伪标签_防伪标签印刷_防伪标签厂家-510品保防伪网 | 青岛代理记账_青岛李沧代理记账公司_青岛崂山代理记账一个月多少钱_青岛德辉财税事务所官网 | 真空泵维修保养,普发,阿尔卡特,荏原,卡西亚玛,莱宝,爱德华干式螺杆真空泵维修-东莞比其尔真空机电设备有限公司 | 科昊仪器超纯水机系统-可成气相液氮罐-美菱超低温冰箱-西安昊兴生物科技有限公司 | 潜水搅拌机-双曲面搅拌机-潜水推进器|奥伯尔环保 | 无线对讲-无线对讲系统解决方案-重庆畅博通信| 广东佛电电器有限公司|防雷开关|故障电弧断路器|智能量测断路器 广东西屋电气有限公司-广东西屋电气有限公司 | 电动葫芦|手拉葫芦|环链电动葫芦|微型电动葫芦-北京市凌鹰起重机械有限公司 | 北京森语科技有限公司-模型制作专家-展览展示-沙盘模型设计制作-多媒体模型软硬件开发-三维地理信息交互沙盘 | 深圳工程师职称评定条件及流程_深圳职称评审_职称评审-职称网 | 游泳池设备安装工程_恒温泳池设备_儿童游泳池设备厂家_游泳池水处理设备-东莞市君达泳池设备有限公司 | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 胀套-锁紧盘-风电锁紧盘-蛇形联轴器「厂家」-瑞安市宝德隆机械配件有限公司 | 钢绞线万能材料试验机-全自动恒应力两用机-混凝土恒应力压力试验机-北京科达京威科技发展有限公司 | 【孔氏陶粒】建筑回填陶粒-南京/合肥/武汉/郑州/重庆/成都/杭州陶粒厂家 | 国资灵活用工平台_全国灵活用工平台前十名-灵活用工结算小帮手 | 泰安塞纳春天装饰公司【网站】| 影视模板素材_原创专业影视实拍视频素材-8k像素素材网 | 自动钻孔机-全自动数控钻孔机生产厂家-多米(广东)智能装备有限公司 | 河南砖机首页-全自动液压免烧砖机,小型砌块水泥砖机厂家[十年老厂] | 进口试验机价格-进口生物材料试验机-西安卡夫曼测控技术有限公司 | 防火窗_耐火窗_防火门厂家_防火卷帘门-重庆三乐门业有限公司 | 高效节能电机_伺服主轴电机_铜转子电机_交流感应伺服电机_图片_型号_江苏智马科技有限公司 | 定坤静电科技静电消除器厂家-除静电设备 | 便携式高压氧舱-微压氧舱-核生化洗消系统-公众洗消站-洗消帐篷-北京利盟救援 | 苹果售后维修点查询,苹果iPhone授权售后维修服务中心 – 修果网 拼装地板,悬浮地板厂家,悬浮式拼装运动地板-石家庄博超地板科技有限公司 |