Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在处理大型数据集时减少内存流失_Java_Performance_Memory - Fatal编程技术网

Java 在处理大型数据集时减少内存流失

Java 在处理大型数据集时减少内存流失,java,performance,memory,Java,Performance,Memory,Java倾向于创建大量对象,在处理大型数据集时需要对这些对象进行垃圾收集。当从数据库流式传输大量数据、创建报告等时,这种情况相当频繁。是否有减少内存流失的策略 在本例中,基于对象的版本花费大量时间(2秒以上)生成对象并执行垃圾收集,而布尔数组版本只需一小部分时间就可以完成,而没有任何垃圾收集 在处理大型数据集时,如何减少内存流失(需要大量垃圾收集) java -verbose:gc -Xmx500M UniqChars ... ---------------- [GC 495441K->4

Java倾向于创建大量对象,在处理大型数据集时需要对这些对象进行垃圾收集。当从数据库流式传输大量数据、创建报告等时,这种情况相当频繁。是否有减少内存流失的策略

在本例中,基于对象的版本花费大量时间(2秒以上)生成对象并执行垃圾收集,而布尔数组版本只需一小部分时间就可以完成,而没有任何垃圾收集

在处理大型数据集时,如何减少内存流失(需要大量垃圾收集)

java -verbose:gc -Xmx500M UniqChars
...
----------------
[GC 495441K->444241K(505600K), 0.0019288 secs] x 45 times
70000007
================
70000007



import java.util.HashSet;
import java.util.Set;
public class UniqChars {
    static String a=null;
    public static void main(String [] args) {
            //Generate data set
            StringBuffer sb=new StringBuffer("sfdisdf");
            for (int i =0; i< 10000000; i++) {
                    sb.append("sfdisdf");
            }
            a=sb.toString();
            sb=null;  //free sb
            System.out.println("----------------");
            compareAsSet();
            System.out.println("================");
            compareAsAry();
    }

    public static void compareAsSet() {
            Set<String> uniqSet = new HashSet<String>();
            int n=0;
            for(int i=0; i<a.length(); i++) {
                    String chr = a.substring(i,i);
                    uniqSet.add(chr);
                    n++;
            }
            System.out.println(n);
    }

    public static void compareAsAry() {
            boolean uniqSet[] = new boolean[65536];
            int n=0;
            for(int i=0; i<a.length(); i++) {
                    int chr = (int) a.charAt(i);
                    uniqSet[chr]=true;
                    n++;
            }
            System.out.println(n);
    }
}
java-verbose:gc-Xmx500M UniqChars
...
----------------
[GC 495441K->444241K(5056000K),0.0019288秒]x 45次
70000007
================
70000007
导入java.util.HashSet;
导入java.util.Set;
公共类UniqChars{
静态字符串a=null;
公共静态void main(字符串[]args){
//生成数据集
StringBuffer sb=新的StringBuffer(“sfdisdf”);
对于(int i=0;i<10000000;i++){
sb.附加(“sfdisdf”);
}
a=某人在做某事;
sb=null;//释放sb
系统输出打印项次(“------------------------------”);
compareaset();
System.out.println(“============================”);
比较的();
}
公共静态无效比较集(){
Set uniqSet=new HashSet();
int n=0;

对于(inti=0;i,在您的示例中,您的两个方法所做的事情非常不同

compareaset()
中,您将生成相同的4个字符串(“s”、“d”、“f”和“i”),并调用String.hashCode()和String.equals(String)(当您尝试添加它们时,HashSet会这样做)7000007次。最终得到的是一个大小为4的HashSet。在执行此操作时,您每次都在分配String.substring对象(int,int)返回值,每当“新”一代垃圾收集器被填满时,该值将强制执行次收集

compareAsAry()中
您已经分配了一个数组65536个元素,其中的一些值发生了更改,然后当方法返回时,它就超出了范围。这是一个单堆内存操作,而不是在
compareaset
中完成的7000007。您确实有一个局部int变量被更改7000007次,但这种情况发生在堆栈内存中,而不是在堆内存中。Thi与另一个方法(基本上只是数组)相比,s方法在堆中不会产生那么多垃圾

关于搅动,您可以选择回收对象或调整垃圾收集器

一般来说,字符串是不可变的,因此不可能回收,尽管VM可能会执行内部操作,但这只会减少总内存占用,而不会减少垃圾流失。可以针对上述场景生成一个回收的解决方案,但实现将是脆弱和不灵活的

调整垃圾收集器,使“新”一代更大,可以减少方法调用期间必须执行的收集总数,从而提高调用的吞吐量。通常,您也可以增加堆大小,这将完成相同的任务

public static void compareLength() {
    // All the loop does is count the length in a complex way.
    System.out.println(a.length());
}

// I assume you intended to write this.
public static void compareAsBitSet() {
    BitSet uniqSet = new BitSet();
    for(int i=0; i<a.length(); i++)
        uniqSet.set(a.charAt(i));
    System.out.println(uniqSet.size());
}
为了进一步阅读Java6中的垃圾收集器调优,我推荐下面链接的Oracle白皮书


在您的示例中,您的两种方法所做的事情非常不同

compareaset()
中,您将生成相同的4个字符串(“s”、“d”、“f”和“i”),并调用String.hashCode()和String.equals(String)(当您尝试添加它们时,HashSet会这样做)7000007次。最终得到的是一个大小为4的HashSet。在执行此操作时,您每次都在分配String.substring对象(int,int)返回值,每当“新”一代垃圾收集器被填满时,该值将强制执行次收集

compareAsAry()中
您已经分配了一个数组65536个元素,其中的一些值发生了更改,然后当方法返回时,它就超出了范围。这是一个单堆内存操作,而不是在
compareaset
中完成的7000007。您确实有一个局部int变量被更改7000007次,但这种情况发生在堆栈内存中,而不是在堆内存中。Thi与另一个方法(基本上只是数组)相比,s方法在堆中不会产生那么多垃圾

关于搅动,您可以选择回收对象或调整垃圾收集器

一般来说,字符串是不可变的,因此不可能回收,尽管VM可能会执行内部操作,但这只会减少总内存占用,而不会减少垃圾流失。可以针对上述场景生成一个回收的解决方案,但实现将是脆弱和不灵活的

调整垃圾收集器,使“新”一代更大,可以减少方法调用期间必须执行的收集总数,从而提高调用的吞吐量。通常,您也可以增加堆大小,这将完成相同的任务

public static void compareLength() {
    // All the loop does is count the length in a complex way.
    System.out.println(a.length());
}

// I assume you intended to write this.
public static void compareAsBitSet() {
    BitSet uniqSet = new BitSet();
    for(int i=0; i<a.length(); i++)
        uniqSet.set(a.charAt(i));
    System.out.println(uniqSet.size());
}
为了进一步阅读Java6中的垃圾收集器调优,我推荐下面链接的Oracle白皮书


正如其中一条评论所指出的,这是您的代码,而不是Java在内存搅动方面的错误。因此,让我们看看您编写的这段代码是如何从StringBuffer中构建一个非常大的字符串的。对其调用toString()。然后对循环中的非常大的字符串调用substring(),并创建一个新的.length()字符串。然后在一个数组上执行一些就地垃圾处理,由于没有对象创建,执行速度非常快,但最终会将其写入一个巨大数组中相同的5-6个位置。浪费很多?那么您认为会发生什么?丢弃StringBuffer并使用StringBuilder,因为它不是完全同步的