Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.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 HashSet与ArrayList CPU使用率高_Java_Performance_Arraylist_Hashset - Fatal编程技术网

Java HashSet与ArrayList CPU使用率高

Java HashSet与ArrayList CPU使用率高,java,performance,arraylist,hashset,Java,Performance,Arraylist,Hashset,我有104k个字符串值,其中89k是唯一的。我想检查此列表中是否存在字符串 这是我的类及其方法,保存了所有这些记录 public class TestClass { private static TestClass singletonObj = null; private List<String> stringList= null; public static synchronized TestClass getInstance() { if

我有104k个字符串值,其中89k是唯一的。我想检查此列表中是否存在字符串

这是我的类及其方法,保存了所有这些记录

public class TestClass {
    private static TestClass singletonObj = null;
    private List<String> stringList= null;

    public static synchronized TestClass getInstance() {
        if(singletonObj == null) {
            singletonObj = new TestClass();
        }
        return singletonObj;
    }


    public boolean isValidString(String token) {
        if(stringList == null) {
            init();
        }
        if(stringList != null && token != null && !token.isEmpty())
            return stringList.contains(token.toLowerCase());
        return false;
    }

    private init() {
     stringList = new ArrayList<String>();
     // put all 104k values in this data structure.
    }
}
公共类TestClass{
私有静态测试类singletonObj=null;
私有列表stringList=null;
公共静态同步测试类getInstance(){
if(singletonObj==null){
singletonObj=newtestclass();
}
返回singletonObj;
}
公共布尔值isValidString(字符串标记){
if(stringList==null){
init();
}
if(stringList!=null&&token!=null&&token.isEmpty())
返回stringList.contains(token.toLowerCase());
返回false;
}
私有init(){
stringList=新的ArrayList();
//将所有104k值放入此数据结构中。
}
}

我的应用程序尝试同时使用这个
isValidString()
方法,每秒大约有20个请求。这很好,但当我尝试将数据结构更改为
HashSet
时,CPU使用率非常高。根据我的理解,Hashset应该比ArrayList[o(n)]性能更好。有人能解释一下为什么会发生这种情况吗?

JDK
HashSet
构建在一个
HashMap
之上,其中value是一个单一的“present”对象。这意味着HashSet的内存消耗与HashMap相同:为了存储大小值,您需要
32*大小+4*容量
字节(加上值的大小)

对于
ArrayList
,它是java.util.ArrayList的容量乘以参考大小
(32位4字节,64位8字节)+[对象头+一个int和一个references]

因此,HashSet绝对不是一个内存友好的集合

取决于您使用的是
32位
还是
64位
VM。也就是说,与ArrayList相比,
8字节
引用会对HashSet造成更大的伤害——根据链接的内存消耗图表,每个引用添加一个额外的
4字节
,使ArrayList每个元素最多
~12字节,HashSet每个元素最多
~52字节。)

ArrayList是使用对象数组实现的。下图显示了32位Java运行时上ArrayList的内存使用和布局:

32位Java运行时上ArrayList的内存使用和布局

上图显示,当创建
ArrayList
时,结果是使用
32字节
内存的
ArrayList
对象,以及默认大小为
10
的对象数组,对于空
ArrayList
,总共
88字节
内存。这意味着
ArrayList
的大小不准确,因此具有默认容量,恰好是
10个条目

ArrayList的属性
默认容量
-10

空大小
-88字节

开销
-48字节加上每个条目4字节

开销
用于10K收集~40K

搜索/插入/删除性能
-O(n)-所用时间与元素数量成线性关系

HashSet的功能比HashMap少,因为它不能包含多个空条目,也不能有重复条目。该实现是围绕HashMap的包装器,HashSet对象管理允许放入HashMap对象的内容。限制HashMap功能的附加功能意味着hashset的内存开销略高

32位Java运行时上哈希集的内存使用和布局

上图显示了java.util.HashSet对象的浅堆(单个对象的内存使用量)(以字节为单位)和保留堆(单个对象及其子对象的内存使用量)(以字节为单位)。浅堆大小为
16字节
,保留堆大小为
144字节
。创建哈希集时,其默认容量(可放入该集的条目数)为
16条
。当以默认容量创建哈希集且没有任何条目放入该集时,它将占用144个字节。这是HashMap内存使用量的额外
16字节

下表显示了哈希集的属性:

哈希集的属性
默认容量
-16个条目

空大小
-144字节

开销
-16字节加上HashMap开销

10K集合的开销
-16字节加上HashMap开销

搜索/插入/删除性能
-O(1)- 所用的时间是常数时间,与元素的数量无关
(假设没有哈希冲突)

我的猜测是,
HashSet
是一种基于哈希的结构,从将每个字符串插入HashSet的那一刻起,即在方法
init
中,计算每个字符串的hashCode。这可能是CPU变高的时期,这是我们在迭代结构值时为获得更好的吞吐量而付出的代价的一部分

如果我是对的,在方法
init
结束后,CPU应该下降,程序的速度应该大大提高,这就是使用HashSet的好处

顺便说一下:优化的一个可靠方法是预先确定结构尺寸:

  • ArrayList的初始大小应等于将包含的最大元素数
  • 并将初始大小设置为大于最大值1.7
顺便说一句:
String的标准哈希算法。hash
计算字符串的所有字符。也许你可以满足于只计算前100个字符,例如(d
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;

public class TestClass {
    private static TestClass singletonObj = null;
    //private List<String> stringList = null;

    private HashSet<String> stringList = null;

    public static synchronized TestClass getInstance() {
        if (singletonObj == null) {
            singletonObj = new TestClass();
        }
        return singletonObj;
    }

    public boolean isValidString(String token) {
        if (stringList == null) {
            init();
        }
        if (stringList != null && token != null && !token.isEmpty())
            return stringList.contains(token.toLowerCase());
        return false;
    }

    private void init() {
        String dictDir = "C:\\Users\\Richard\\Documents\\EOWL_CSVs";
        File[] csvs = (new File(dictDir)).listFiles();
        stringList = new HashSet<String>();
        Scanner inFile = null;

        for (File f : csvs) {
            try {
                inFile = new Scanner(new FileReader(f));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                System.exit(1);
            }

            while (inFile.hasNext()) {
                stringList.add(inFile.next().toLowerCase()
                        .replaceAll("[^a-zA-Z ]", ""));
            }
            inFile.close();
        }

        System.out.println("Dictionary initialised with " + stringList.size()
                + " members");
    }
}
import java.io.FileNotFoundException;

public class DictChecker extends Thread {

    TestClass t = null;
    public static int classId = 0;
    String className = null;
    
    
    public void doWork()
    {
        String testString = "Baby";
        if (t.isValidString(testString))
        {
            System.out.println("Got a valid string " + testString + " in class " + className);
        }
        else
        {
            System.out.println(testString + " not in the dictionary");
        }
    }
    
    public void run()
    {
        while (true)
        {
            try {
                DictChecker.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            doWork();
        }
    }
    
    public DictChecker()
    {
        t = TestClass.getInstance();
        className = "dChecker" + classId;
        classId += 1;
        System.out.println("Initialised " + className + " in thread " + this.getName());
    }
    
    public static void main(String[] args) throws FileNotFoundException
    {
        for (int i = 0; i < 20; i++)
        {
             (new DictChecker()).start();
             try {
                DictChecker.sleep(50);//simply to distribute load over the second
            } catch (InterruptedException e) {
                e.printStackTrace();
            } 
        }
    }
}