久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

Java“為"語句實現(xiàn)防止垃圾收集

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

問題描述

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

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

總結:

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

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

例子:

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

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);
    }
}

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

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

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

在運行時我有:

在第一次分配內(nèi)存之前:1251k of max 176640k

Before first memory allocating: 1251k of max 176640k

第一次內(nèi)存分配后: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)

再次嘗試在方法體中分配內(nèi)存:

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() 內(nèi)部,我嘗試分配列表,對其進行迭代,丟棄對列表的引用,(可選)強制垃圾收集并再次分配類似的列表.但由于內(nèi)存不足,我無法分配第二個數(shù)組.

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.

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

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

為了避免函數(shù)體內(nèi)出現(xiàn)這種 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!!!

然后輸出如下:

在第一次分配內(nèi)存之前:1251k of max 176640k

Before first memory allocating: 1251k of max 176640k

第一次內(nèi)存分配后:最大 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!)

再次嘗試在方法體中分配內(nèi)存:

Try to allocate memory in the method body again:

二級內(nèi)存分配后: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迭代的情況下,在丟棄對字符串的引用后成功收集垃圾,并第二次分配(在函數(shù)體內(nèi))和第三次分配(在方法外).

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 引用一直停留在范圍內(nèi).您無權訪問引用以使其無效,并且 GC 無法執(zhí)行收集.

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 中指定,但我還沒有找到),但恕我直言,如果編譯器創(chuàng)建了一些實例,它應該關心在之后從范圍中丟棄它們使用.

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.

這就是我期望實現(xiàn) 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 示例中的調(diào)用) - 在第二次字符串分配期間,JVM 必須 釋放丟棄的內(nèi)存.

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$ 持有對數(shù)組 data 的引用,一旦未引用該數(shù)組,就會阻止 GC 收集該數(shù)組不再在方法內(nèi)部.此錯誤已通過生成此代碼修復:

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 創(chuàng)建的任何引用類型的合成變量設置為 null 以轉換循環(huán).如果我們談論的是原始類型的數(shù)組,那么最后一個對 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“為"語句實現(xiàn)防止垃圾收集的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

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

相關文檔推薦

Java Remove Duplicates from an Array?(Java從數(shù)組中刪除重復項?)
How to fix Invocation failed Unexpected Response from Server: Unauthorized in Android studio(如何修復調(diào)用失敗來自服務器的意外響應:在 Android 工作室中未經(jīng)授權)
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)
主站蜘蛛池模板: 色网站视频 | 欧美中文字幕一区 | 日日草天天干 | 欧美国产激情二区三区 | 中文二区| 亚洲欧美日韩成人在线 | 欧美高清一区 | 国产精品国产三级国产aⅴ浪潮 | 国产在线精品一区二区 | 亚洲精品电影网在线观看 | 国产精品成人国产乱一区 | 国产精品久久久久无码av | 国产精品96久久久久久 | 99pao成人国产永久免费视频 | 国产在线精品一区二区 | 日韩精品一二三 | 蜜桃在线视频 | 国产精品亚洲精品久久 | 亚洲精品久久久久久首妖 | 精品国产乱码久久久久久蜜柚 | 成人精品一区二区三区 | 国产精品久久久久久久久免费桃花 | 国产精品99久久久久久动医院 | 日韩一区中文字幕 | 久久国产综合 | 一级免费在线视频 | 性高湖久久久久久久久aaaaa | 免费一级片 | 中文字幕高清 | 老司机精品福利视频 | 91资源在线| 一区二区在线免费观看 | 免费九九视频 | 天天插天天干 | 美女视频一区 | 91精品一区二区三区久久久久 | 欧美综合一区 | 国产成人精品免高潮在线观看 | 日韩欧美国产不卡 | 亚洲精品美女视频 | a国产一区二区免费入口 |