简单数据结构的Java内存使用

简单数据结构的Java内存使用,java,string,memory,jvm,hashmap,Java,String,Memory,Jvm,Hashmap,我想用java实现对缓存的精确测量。请告诉我这种方法是否可行 我有一个将字符串映射到字符串数组的hashmap。有什么方法可以很好地了解这个数据结构吗 如何获得字符串的大小?调用String.toByte()并为保存对象的开销添加一些加号 字符串数组是所有字符串的总和吗?还是有一些开销 hashmap是否也有一些过度加载,可能是将对象包装到某个条目对象中 对于映射中所有未使用的空间,hashmap仍会分配一些空间,我是否可以对映射中所有未使用的空间求和2*null指针 我很高兴有特别的答案,也为

我想用java实现对缓存的精确测量。请告诉我这种方法是否可行

我有一个将字符串映射到字符串数组的hashmap。有什么方法可以很好地了解这个数据结构吗

  • 如何获得字符串的大小?调用String.toByte()并为保存对象的开销添加一些加号

  • 字符串数组是所有字符串的总和吗?还是有一些开销

  • hashmap是否也有一些过度加载,可能是将对象包装到某个条目对象中

  • 对于映射中所有未使用的空间,hashmap仍会分配一些空间,我是否可以对映射中所有未使用的空间求和
    2*null指针


  • 我很高兴有特别的答案,也为我指出了正确的方向。

    我认为一个很好的实用方法是使用内存分析器,例如。

    你试过吗?这可能会告诉您想要什么,尽管JavaDoc声称这只是一个估计值。

    1)让我们假设一下,尽管不能保证(不同的JVM可以采取不同的行动)

    2) 字符串加上保存对象(数组)的开销之和

    3) 当然,很多。对象被包装成条目,然后这些条目被存储到一个内部HashSet中,等等。。。至少在Oracle JVM中是这样

    4) 地图上没有“未使用”的空间。。。你什么意思

    总而言之,不幸的是,这些问题都没有精确的答案。它取决于虚拟机、GC、操作系统等。。。探查器可以为您提供一些与一种配置相关的有用信息,但这是您希望得到的最多的信息


    这是出于设计:Java及其垃圾收集器希望您永远不必担心内存分配和管理细节。大多数时候都很棒,对你来说这是一种负担。无论如何,您为什么有这样的需求?

    量化内存使用量的简单方法是使用以下各项:
    jmap-histo:live
    (java进程的进程id)

    这将为您提供堆的直方图。对于每个Java类,将打印对象数、内存大小(字节)和完全限定的类名。
    您还可以执行以下操作:
    jmap-转储:实时pid

    以hprof二进制格式转储Java堆。
    我会更深入地研究。当您的瓶颈是java内存时,它非常有用
    例如,您可以创建一个脚本,该脚本每30秒执行一次jmap-histo。然后,您可以绘制输出图,并查看在java类中创建的每个对象的内存演变

    下面是jmap-histo的一个示例:

    $ jmap -histo `pgrep java` |more
    num   #instances    #bytes  class name
    --------------------------------------
      1:    224437    27673848  [C
      2:     38611    23115312  [B
      3:     47801    12187536  [I
      4:    208624     8344960  java.lang.String
      5:     45332     6192904  <constMethodKlass>
      6:     45332     5450864  <methodKlass>
      7:      3889     4615536  <constantPoolKlass>
      8:     45671     4193136  [Ljava.lang.Object;
      9:     66203     3222312  <symbolKlass>
     10:      3889     3192264  <instanceKlassKlass>
     11:      3455     2999296  <constantPoolCacheKlass>
     12:     19754     1106224  java.nio.HeapCharBuffer
    
    $jmap-histo`pgrep java`|更多
    num#实例#字节类名
    --------------------------------------
    1:224437 27673848[C]
    2:386112311512[B]
    3:4780112187536[I]
    4:208624 8344960 java.lang.String
    5:     45332     6192904  
    6:     45332     5450864  
    7:      3889     4615536  
    8:456714193136[Ljava.lang.Object;
    9:     66203     3222312  
    10:      3889     3192264  
    11:      3455     2999296  
    12:19754 1106224 java.nio.HeapCharBuffer
    
    更多例子



    另外,配置您的进程也是一个不错的选择。
    我建议使用或

    对象实例所隐含的实际内存开销取决于JVM实现的一些内部细节,可能很难定义,因为它可以在对象的整个生命周期内更改(在垃圾收集器中,对象可以“移动”)使用不同内存管理结构的代之间)

    一个非常粗略的近似值是,任何对象的每个实例都包含两个“字”(32位机器上有两个32位值,64位机器上有两个64位值);其中一个字或多或少是指向该对象的
    实例的指针,另一个字保存某些对象状态,例如该对象的监视器(您用
    synchronized
    锁定的对象)。然后是对象字段。对于数组,数组长度必须写入对象中的某个位置,还必须写入值

    此时,请查看Java类的源代码(在JDK发行版中查找名为
    src.zip
    的文件)。在
    String.Java
    文件中,我们可以看到,在内部,
    String
    实例有四个字段:对
    char
    值数组的引用和三个
    int
    (一个是数组中第一个字符串的索引,第二个是字符串长度,第三个缓存字符串哈希代码)。因此,对于32位机器,您可以估计n个字符的
    字符串
    实例的最小内存使用量为以下总和:

    • 两个32位字,用于
      字符串
      实例对象头
    • 用于
      字符串
      实例字段的四个32位字
    • 数组实例头和长度的三个32位字
    • n字符本身的16位字(a
      char
      为16位)
    这只是一个最小值,因为
    String
    实例仅引用内部字符数组的一块,因此数组内存大小可能更大。另一方面,字符数组可能在多个
    String
    实例之间共享。此结构允许
    String.substring()
    速度非常快:新的
    字符串
    实例在内部使用相同的数组,因此不涉及数据复制;但这也意味着,如果您有一个大字符串,取其中的一小子字符串,并存储该小子字符串,那么实际上您也将大数组保留在RAM中(对于
    String
    实例
    str
    ,您可以创建
    newstring(str)
    ,以获得一个新实例,该实例将在内部使用新分配和精简的数组实例)。好的一面是,如果您有两个字符串,