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

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

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

問(wèn)題描述

UPD 21.11.2017:該錯(cuò)誤已在 JDK 中修復(fù),請(qǐng)參閱 Vicente Romero 的評(píng)論

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

總結(jié):

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

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

例子:

如果我有下一個(gè)代碼,它會(huì)分配一個(gè)包含隨機(jī)內(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)存編譯和運(yùn)行它,像這樣(180mb):

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

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

在運(yùn)行時(shí)我有:

在第一次分配內(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

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

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)部,我嘗試分配列表,對(duì)其進(jìn)行迭代,丟棄對(duì)列表的引用,(可選)強(qiáng)制垃圾收集并再次分配類似的列表.但由于內(nèi)存不足,我無(wú)法分配第二個(gè)數(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ù)體之外,我可以成功強(qiáng)制垃圾回收(可選)并再次分配相同的數(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

在方法體中強(qiáng)制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:

二級(jí)內(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

所以,在沒(méi)有for迭代的情況下,在丟棄對(duì)字符串的引用后成功收集垃圾,并第二次分配(在函數(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).

我的假設(shè):

for 語(yǔ)法構(gòu)造被編譯成

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

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

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

并且看起來(lái)這個(gè) iter 引用一直停留在范圍內(nèi).您無(wú)權(quán)訪問(wèn)引用以使其無(wú)效,并且 GC 無(wú)法執(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 中指定,但我還沒(méi)有找到),但恕我直言,如果編譯器創(chuàng)建了一些實(shí)例,它應(yīng)該關(guān)心在之后從范圍中丟棄它們使用.

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.

這就是我期望實(shí)現(xiàn) for 語(yǔ)句的方式:

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 編譯器和運(yùn)行時(shí)版本:

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)

注意:

  • 問(wèn)題不在于編程風(fēng)格、最佳實(shí)踐、約定等等,問(wèn)題是關(guān)于Java的效率平臺(tái).

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

問(wèn)題不在于 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.

對(duì)測(cè)試java類的引用, 在線編譯器測(cè)試(但是這個(gè)資源只有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)

推薦答案

感謝您的錯(cuò)誤報(bào)告.我們已修復(fù)此錯(cuò)誤,請(qǐng)參閱 JDK-8175883.正如這里在 enhanced for 的情況下所評(píng)論的,javac 正在生成合成變量,因此對(duì)于如下代碼:

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$];
}

如上所述,這種轉(zhuǎn)換方法意味著合成變量 arr$ 持有對(duì)數(shù)組 data 的引用,一旦未引用該數(shù)組,就會(huì)阻止 GC 收集該數(shù)組不再在方法內(nèi)部.此錯(cuò)誤已通過(guò)生成此代碼修復(fù):

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;

這個(gè)想法是將 javac 創(chuàng)建的任何引用類型的合成變量設(shè)置為 null 以轉(zhuǎn)換循環(huán).如果我們談?wù)摰氖窃碱愋偷臄?shù)組,那么最后一個(gè)對(duì) null 的賦值不是由編譯器生成的.該錯(cuò)誤已在 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

這篇關(guān)于Java“為"語(yǔ)句實(shí)現(xiàn)防止垃圾收集的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

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

相關(guān)文檔推薦

Java Remove Duplicates from an Array?(Java從數(shù)組中刪除重復(fù)項(xiàng)?)
How to fix Invocation failed Unexpected Response from Server: Unauthorized in Android studio(如何修復(fù)調(diào)用失敗來(lái)自服務(wù)器的意外響應(yīng):在 Android 工作室中未經(jīng)授權(quán))
AES encryption, got extra trash characters in decrypted file(AES 加密,解密文件中有多余的垃圾字符)
AES Error: Given final block not properly padded(AES 錯(cuò)誤:給定的最終塊未正確填充)
Detecting incorrect key using AES/GCM in JAVA(在 JAVA 中使用 AES/GCM 檢測(cè)不正確的密鑰)
AES-256-CBC in Java(Java 中的 AES-256-CBC)
主站蜘蛛池模板: 日韩视频精品 | 日韩精品在线看 | h免费观看 | 久久久久一区二区三区 | 免费在线观看一区二区 | 在线激情视频 | 亚洲久草| 91精品一区二区三区久久久久 | 国产视频一视频二 | 日韩成人免费视频 | 久久久精品一区 | 欧美不卡一区 | 中文字幕av在线播放 | 91 视频网站 | 亚洲美女av网站 | 亚洲成人网在线观看 | 日韩福利 | 亚洲最新在线视频 | 国产精品乱码一区二三区小蝌蚪 | 伊人久久精品 | 欧洲精品一区 | 亚洲人成在线观看 | 国产精品一区二区在线 | 成人av一区二区三区 | 国产国语精品 | 久久久夜色精品亚洲 | 日日干夜夜操天天操 | 91精品久久久久久久久久入口 | 国产精品久久一区二区三区 | 久久一二 | 欧美久久国产 | 中文精品一区二区 | 高清视频一区二区三区 | 人人干视频在线 | 欧美日韩在线一区二区三区 | 中文字幕 欧美 日韩 | 国产在线精品一区二区 | 尤物在线视频 | 欧美一区二区三区在线 | 日韩中文一区二区三区 | 亚洲精选一区二区 |