Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.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/0/performance/5.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 Leaks - Fatal编程技术网

构建内存效率高的Java应用程序的最佳实践是什么?

构建内存效率高的Java应用程序的最佳实践是什么?,java,performance,memory-leaks,Java,Performance,Memory Leaks,Java程序可能非常需要内存。例如,一个Double对象有24个字节:8个字节的数据和16个字节的JVM开销。通常,表示基元类型的对象非常昂贵 Java标准库中的任何集合也是如此。甚至还有一些违反直觉的事实,例如HashSet比HashMap更需要内存,因为HashSet内部包含HashMap) 在高性能设置中对数据建模和对象委派时,您能否提出一些建议,以减轻Java的这些“弱点”?如果您有高性能限制,并且需要将集合用于简单类型,您可以查看一些Java基元集合的实现 其中包括: 另外,

Java程序可能非常需要内存。例如,一个
Double
对象有24个字节:8个字节的数据和16个字节的JVM开销。通常,表示基元类型的对象非常昂贵

Java标准库中的任何集合也是如此。甚至还有一些违反直觉的事实,例如
HashSet
HashMap
更需要内存,因为
HashSet
内部包含
HashMap


在高性能设置中对数据建模和对象委派时,您能否提出一些建议,以减轻Java的这些“弱点”?

如果您有高性能限制,并且需要将集合用于简单类型,您可以查看一些Java基元集合的实现

其中包括:


另外,请参考以下问题:

注意早期优化。 看


虽然不知道应用程序或运行时环境的确切要求,但根据我的经验,java能够处理我抛出它的任何东西。如果性能或垃圾收集(您标记为内存泄漏)是一个问题,那么在演示/概念验证应用程序上进行一些评测可能是一个不错的选择。

取决于应用程序,但一般来说

  • 在(并行)基元数组中布局数据结构

  • 尝试制作大的“平面”对象,内联其他合理的子结构

  • 专门化原语集合

  • 重用对象、使用对象池、线程局部变量

  • 滚蛋

我不能说这些实践是“最好的”,因为不幸的是,它们使您遭受痛苦,失去了使用Java的意义,降低了代码库的灵活性、可支持性、可靠性、可测试性和其他“良好”属性

但是,它们确实可以降低内存占用和GC压力。

Luís Bianchin已经为您提供了一些用Java实现最佳集合的库。 然而,您似乎特别关注Java集合的内存分配。在这种情况下,有几个选择是非常直接的

  • 缓存
  • 您可以使用缓存来限制集合(缓存)可以分配的内存。通过这样做,您只需在主内存中加载最常用的条目,而不需要从磁盘/网络/任何形式加载整个数据集。我强烈推荐,因为它有很好的文档记录,而且非常成熟

  • 持久集合
  • 有时缓存并不能解决您的问题。例如,在ETL解决方案中,您可能知道每个条目只加载一次。对于这个场景,我建议使用持久收集。这些是磁盘存储的集合,比传统数据库快得多,但有很好的JavaAPI。 p收藏对我来说是最好的图书馆

  • 配置文件内存使用情况
  • 除此之外,如果您真的想知道程序内存分配的实际状态,我强烈建议您使用探查器。这样,您不仅可以知道集合占用了多少内存,还可以知道GC随时间的变化情况

    事实上,只有在存在实际内存问题的情况下,才应该尝试Java集合和数据结构的替代方案,而探查器可以告诉您这一点

    JDK有一个名为VisualVM的分析器,它做得很好。尽管如此,如果你能负担得起的话,我建议你使用一个商业分析器。与VisualVM相比,商业分析器对应用程序性能的影响通常较小

  • 内存优化数据与网络配合良好

  • 最后,它与你的问题没有严格的关系,但它是紧密相连的。如果您想将Java对象序列化为最佳的二进制表示形式,我建议您使用Java中的Google Protocol Buffers。协议缓冲区是传输数据结构的理想选择,因为网络使用尽可能少的带宽,并且编码/解码速度非常快。

    您可以做很多事情

    以下是一些问题和解决方案:

  • 在java中更改字符串的值时,该字符串实际上不会被覆盖。而是创建一个新字符串来替换旧字符串。但是,旧字符串仍然存在。这可能是一个问题时,有效地使用RAM是一个问题。以下是解决此问题的一些方法:

    • 当使用字符串指定对象的“状态”或其他只能具有一组特定可能值的内容时,不要使用字符串。而是使用枚举。如果您不知道枚举是什么或如何使用枚举
    • 如果您使用字符串作为变量,而该变量的值在程序中的某个点会发生变化,请不要像通常那样定义字符串。相反,使用java.lang包中的StringBuilder类。StringBuilder是一个用于创建字符串并更改其值的类。此类处理字符串的方式与通常的不同。当它用于更改字符串的值时,StringBuilder不会创建具有不同值的重复字符串来替换旧字符串,而是实际更改原始字符串的值。因此,由于您没有创建重复的字符串,因此可以节省RAM
  • 写入器和读取器对象(如文件写入器和文件读取器)也占用RAM。如果你有很多,这也会导致问题。以下是一些解决方案:

    • 所有读写器对象都有一个名为close()的方法。正如您可能猜到的,它关闭writer或reader对象。它所做的只是去掉reader或writer对象。当你有读者或作家的时候
      Integer stack[];
      stack = new Integer[10];
      int stackPtr = 0;
      
      // a few push operation on our stack.
      stack[stackPtr++] = new Integer(5);
      stack[stackPtr++] = new Integer(3);
      
      // and pop from the stack again
      --stackPtr;
      --stackPtr;
      
      // at this point, the stack is logically empty, but
      // the Integer objects are still referenced by the array,
      // and are basically leaked.
      
      stack[--stackPtr] = null;