gpt4 book ai didi

java - 内存使用本地变量而不是内联 Java

转载 作者:行者123 更新时间:2023-12-01 16:59:20 25 4
gpt4 key购买 nike

当另一位开发人员正在讨论代码清晰度时。他说使用局部变量会增加内存使用。我们认为它们将被垃圾收集。尤其是如果日志语句调用一个访问数据库/其他外部资源的函数,这尤其是一个坏主意。

但是下面的示例代码似乎支持他的说法 - 即使在使用 jconsole 调用 GC 之后,仍然看到 Worker 类使用的内存比 Worked2 少。有什么想法吗?

可用内存:124629976 - worker 124784720

package test;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class ObjectLife {

public static void main(String[] args) {
// simple multi thread to mimic web app
// ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 3, 110, null, null);
Executor pool = Executors.newFixedThreadPool(3);
String type = "1";

if (args.length > 0) {
type = args[0];
}
Work w = null;
if ("1".equals(type)) {
w = new Worker();
} else {
w = new Worker2();
}
w.init(2);
System.out.println("w type " + w.getClass().getName());
Watch.me.print();
pool.execute(w);
pool.execute(Watch.me);

}

}

class Watch implements Runnable {
long prev = 0;
static Watch me = new Watch();

@Override
public void run() {
while (true) {
try {
Thread.sleep(1100);
} catch (InterruptedException e) {
System.out.println("Intrpt thread " + e);
}
print();
}
}

public void print() {
Runtime r = Runtime.getRuntime();
long free = r.freeMemory();
System.out.println("Free " + free + ", delta " + (free - prev));
System.out.println(", av " + r.maxMemory());
prev = free;
}

}

class Work implements Runnable {
double val = 0;

public void init(double val) {
this.val = val;
}

void do2() {
}

@Override
public void run() {
int cnt = 0;
while (++cnt < 175) {
do2();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Intrpt thread " + e);
}
}
System.gc();
System.out.println("Type, v3, : " + this.getClass().getName());
Watch.me.print();

}

}

class Worker extends Work {

public void do2() {
double local = ++val;
double local2 = local * 2;
System.out.println(" local " + local + " double " + local2);
}
}

class Worker2 extends Work {

public void do2() {
System.out.println(" local " + ++val + " double " + (val * 2));

}

}

为什么 Worker 类会占用更多内存 - 即使多次调用 GC 然后将 Jconsole 与进程断开连接并等待几秒钟? (每 2 秒检查并打印一次。

可以看到代码与work的父类(super class)相同,worker除了do2()方法之外都是相同的

注意:我从 jconsole 连接并在工作循环完成后调用 GC。这个 GC 调用确实有效。调用 MX bean,可以看到可用内存下降。

旁注:我什至注意到,如果我断开 jconsole 与我的应用程序的连接,然后等待 4-5 秒 - 可用内存再次增加(我猜是连接到 jconsole 的头)。这时我进行测量。重点是我做了一些工作,等待 JVM 稳定下来然后进行测量。

运行该程序并使用 jconsole 释放内存的视频 https://www.youtube.com/watch?v=MadBdryX8uk&

jconsole 是一个免费工具,JDK 位于 bin 文件夹中。

编辑了类,这里增加了循环次数,现在无论使用哪个类,内存都是相同的!

其他人可以运行它吗?

package test;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
* Run with param 1 and 2 or change type to "2" and "1" Available memory changes, used jconsole to change force garbage collection.
*
* See video https://www.youtube.com/watch?v=MadBdryX8uk
*/
public class ObjectLife {

public static void main(String[] args) {
// simple multi thread to mimic web app
// ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 3, 110, null, null);
Executor pool = Executors.newFixedThreadPool(3);
String type = "1";

if (args.length > 0) {
type = args[0];
}
Work w = null;
if ("1".equals(type)) {
w = new Worker();
} else {
w = new Worker2();
}
w.init(2);
System.out.println("w type " + w.getClass().getName());
Watch.me.print();
pool.execute(w);
pool.execute(Watch.me);

}

}

class Watch implements Runnable {
long prev = 0;
private int dieCnt = -1;
static Watch me = new Watch();

@Override
public void run() {
while (true) {
try {
Thread.sleep(1100);
} catch (InterruptedException e) {
System.out.println("Intrpt thread " + e);
}
if (dieCnt > -1) {
dieCnt--;

if (dieCnt == 0) {
System.exit(0);
}
}
print();
}
}

public void print() {
Runtime r = Runtime.getRuntime();
long free = r.freeMemory();
System.out.println("Pr v6 Free " + free + ", delta " + (free - prev) + ", av " + r.maxMemory());
prev = free;
}

public void countDown() {
dieCnt = 3;

}

}

class Work implements Runnable {
double val = 0;
double val3 = 0;

public void init(double val) {
this.val = val;
}

void do2() {
}

@Override
public void run() {
int cnt = 0;
while (++cnt < 475) {
do2();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Intrpt thread " + e);
}
}
System.gc();
System.out.println("Type : " + this.getClass().getName());
Watch.me.print();
System.out.println("oink");
try {
Thread.sleep(9100);
} catch (InterruptedException e) {
System.out.println("Intrpt thread " + e);
}
Watch.me.countDown();

}

}

class Worker extends Work {

public void do2() {
double local = ++val;
double local2 = local * 2;
System.out.println(" local " + local + " double " + local2);
val3 = local2 + 1;
}
}

class Worker2 extends Work {

public void do2() {
System.out.println(" local " + ++val + " double " + (val * 2));
val3 = (val * 2) + 1;

}

}
  • 我知道本地变量更具可读性。我喜欢他们。我为他们辩护。
  • 只是对这种行为感到好奇。

最佳答案

首先,System.gc() 可能会运行垃圾收集器;或不。这确实不是测试内存消耗的可靠方法。

参见When does System.gc() do anything了解详情。

下一步:请记住,有一个即时编译器。 JIT 最适合“普通 Java”代码。很多时候,当开发人员试图变得“聪明”并编写“更高效的 Java 代码”时 - 他们最终会比以前更糟糕 - 因为 JIT 无法有效地处理这种“特殊”代码。

编写的程序要清晰易读。他们一生中可能会被阅读数百次;可能是由许多不同的人。所以,我想说的是:让你的代码易于理解更为重要。牢记效率是公平的;但只有在遇到实际问题时才开始“优化”——然后进行适当的分析;例如使用分析器。 “避免局部变量以节省内存”不是“一般”应该做的事情。

关于java - 内存使用本地变量而不是内联 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28937190/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com