java - 如何在无限循环中使用更少的堆空间?

标签 java loops memory-leaks heap-memory heap-dump

我的 java 应用程序的内存使用出现问题。有堆空间和非堆空间。现在我专注于我的堆空间。

我的应用程序是一个SocketServer,它通过DataInputStream获取输入。我正在以字节数组的形式读取信息。我每秒收到的输入量不规则,但我们谈论的是每秒 400 字节到 1.000 字节的空间,峰值可以更高。

由于我的程序是一个服务器,它会无限循环地等待输入。现在我遇到了一个问题,我的堆空间随着时间的推移而不断增加,5-10 分钟内它增加了 0,5MB。

我使用了多个监视器应用程序,例如 jconsole 和 YourProfiler。之后,我尝试在堆转储的帮助下找出答案,我使用 jmap 生成堆转储并使用 Eclipse 内存分析器进行分析。

现在我的问题是,在这个示例代码中,哪个选项更好,或者使用更少的堆空间 1 或 2?

选项 1:

while (true){
byte [] one= new byte [21]; 
do something with one;
byte [] two= new byte [50];
do something with two;
byte [] three= new byte [30];
do something with three;
}

选项 2:

byte [] one;
byte [] two;
byte [] three;
while (true){
one= new byte [21]; 
do something with one;
two= new byte [50];
do something with two;
three= new byte [30];
do something with three;
}

我不知道循环中创建的三个对象会发生什么。这些应该是局部变量,并且只能在循环中可见和访问。但是在一个循环之后,JVM 会删除它们并在下一个循环中创建新的。所以我猜应该不会有内存泄漏?

在第二个选项中,这三个变量是在循环外部声明的,因此它们始终处于 Activity 状态。在循环中,这些对象的引用发生了变化,因此不会有对旧内容的引用,这意味着它被删除,分别由 GC 收集。

在这两个选项中,每秒大约有 4 个圆圈。

预先感谢您的帮助!

JUnit 测试结果:

enter image description here

最佳答案

变量 onetwo Three 只是引用:它们本身不保存值,而只是引用位置在存储实际数组对象的堆中。

因此,两种方法在分配的对象数量方面没有区别。

选项 3:在循环外分配数组,并重用相同的数组:

byte [] one= new byte [21];
byte [] two= new byte [50];
byte [] three= new byte [30];
while (true){
  // If necessary, zero out the arrays so that data from the previous
  // iteration is not used accidentally.
  Arrays.fill(one, (byte) 0);
  Arrays.fill(two, (byte) 0);
  Arrays.fill(three, (byte) 0);

  // Rest of the loop.
}

这会预先分配数组,因此只创建 3 个数组对象,而不是 (3 * #iterations) 数组对象。

请注意,只有在不泄漏对数组的引用的情况下才能使用此方法,例如将它们放入循环体外部的列表中。

<小时/>

为了证明 OP 的两种方法中的内存分配是相同的,请尝试反编译代码:

  public static void inLoop() {
    while (true) {
      byte[] one = new byte[21];
      byte[] two = new byte[50];
      byte[] three = new byte[30];
    }
  }

  public static void outsideLoop() {
    byte[] one;
    byte[] two;
    byte[] three;
    while (true) {
      one = new byte[21];
      two = new byte[50];
      three = new byte[30];
    }
  }

这两种方法反编译为相同字节码:

  public static void inLoop();
    Code:
       0: bipush        21
       2: newarray       byte
       4: astore_0
       5: bipush        50
       7: newarray       byte
       9: astore_1
      10: bipush        30
      12: newarray       byte
      14: astore_2
      15: goto          0

  public static void outsideLoop();
    Code:
       0: bipush        21
       2: newarray       byte
       4: astore_0
       5: bipush        50
       7: newarray       byte
       9: astore_1
      10: bipush        30
      12: newarray       byte
      14: astore_2
      15: goto          0

因此,运行时内存分配必须相同。

关于java - 如何在无限循环中使用更少的堆空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38390755/

相关文章:

java - Apache HttpClient 会在所有 HTTP 5XX 错误上执行抛出 IOException 吗?

php - 如何在 while 循环中创建嵌套列表?

javascript - 列表样式在索引 4000 之后停止显示罗马数字

java - 我将如何使用 while 循环以及 if else 如果用户输入相同的输入两次并且它将再次尝试

javascript - Chrome Profiler Javascript 内存泄漏

linux - Linux 设备上的内存泄漏

javascript - Java Servlet 在无限循环中写入图像

java - 在 Spring 3 MVC 中验证@RequestParam

java - 如何从 Bootstrap 模板编辑导航栏并将其转换为具有相同设计的下拉菜单?

python - 在 Python 中卸载模块