Java应用程序中每个类的成本 - 较少的大类或几个较小的类

Ted*_*ddy 6 java memory performance java-ee

对于添加到Java应用程序的每个新类,内存成本是多少?

  • 拥有超过5000行的类或几个500-1000行类(如果所有这些都是加载的话)是否更好?
  • 每次实例化Object时,唯一的额外内存使用是针对实例变量引用的
  • 对于没有实例变量的5000行类,加载类时的成本比例是多少?类文件的大小是粗略的近似值?
  • jar文件的大小是否表示类将占用的内存的常规或最大大小?

在cruftex的回答后编辑:这是我对课堂分裂的理解:

  • 拆分成逻辑块可以很好地改善代码重用并减少行数
  • 它还使得理解和维护代码变得更容易

这是我对类加载的理解:

  • 首次使用Class加载到内存中(使用的内存大致是类文件的大小)
  • 如果使用JIT,JIT编译器会创建一些额外的机器友好二进制版本,它使用更多的内存
  • 如果使用Hotspot,则只使用机器友好版本优化一些常用类(以平衡内存和速度)
  • 一旦加载了一个类,创建其他实例的开销可以忽略不计(大约50-100个字节?)(假设没有实例变量)
  • 加载类后,类本身永远不会被垃圾回收

这是大致如何运作?

cru*_*tex 5

你的问题无法回答具体问题,所以我一般都会尝试.你的问题针对记忆消耗.但是,如果你节省了内存,那么你的性能很可能会受到影响,这就是所谓的时空权衡.请参阅:http://en.wikipedia.org/wiki/Space%E2%80%93time_tradeoff

保存内存的最简单方法 - 如果您关心程序大小 - 将完全关闭即时编译器.这样就可以保存java类机器代码的程序存储.BTW:有很多VM选项会影响内存消耗!

拥有超过5000行的类或几个500-1000行类(如果所有这些都是加载的话)是否更好?

一般而言,您可能更有可能在较小的单元内更好地重用代码.这意味着,您可以在针对较小尺寸时保存代码行.

如果代码/方法保持不变并且您只是在类之间分配它们,则会为类添加额外的开销.

即使您询问了三位专家并且他们看了代码,他们也会得到不同的答案,因为它在很大程度上取决于您的实际代码,使用模式以及JIT在运行时使用它做了什么.

也就是说,即使是实验也可能导致您走错方向,因为您需要模拟相同的使用模式.

关于这一点的最后一点:看看您的VM加载了多少个类,并确定是否真的值得保存视图.

每次实例化Object时,唯一的额外内存使用是针对实例变量引用的

加上内存管理的持续开销.

对于没有实例变量的5000行类,加载类时的成本比例是多少?类文件的大小是粗略的近似值?

没有JIT:是的.

jar文件的大小是否表示类将占用的内存的常规或最大大小?

不,完全没有,因为类只在需要时加载.

一些忠告:

如果您担心程序的内存使用情况,请首先检查堆两次.我建议使用jmap和eclipse内存分析器.

然后,您可以查看您的类和方法.您可以调试JIT并查看编译方法需要多少空间:-XX:-PrintCompilation.


mer*_*ike 5

对于添加到Java应用程序中的每个新类,在内存方面的成本是多少?

通常没关系。一般而言,各种形式的代码仅占总内存使用的一小部分(例如5%)。因此,即使您确实设法将代码大小减少了一半,总的内存使用量也只会少量减少。

相反,过长的源文件使代码库难以导航,而较大的作用域则使得难以大致了解类的用途以及某些更改是否安全。因此,较长的源文件使修改代码的成本大大增加并且容易出错。

  • 首次使用时,将类加载到内存中(使用的内存大约是类文件的大小)

正确。

  • 如果使用JIT,则JIT编译器会创建一些其他的机器友好的二进制版本,该版本使用更多的内存
  • 如果使用Hotspot,则仅使用机器友好的版本对某些常用类进行优化(以平衡内存和速度)

热点是准时制,因此您在这里重复一遍。但是,是的,JIT确实增加了代码大小(但增加了更多的速度)。

加载类后,创建其他实例的开销可以忽略不计(大约50-100字节?)(假设没有实例变量)

那是特定于JVM的。在Oracle Hotspot JVM上,每个对象的内存开销约为8个字节,如以下程序所示:

public class Test {
    public static void main(String[] args) {
        Object[] array = new Object[10_000_000];
        Runtime rt = Runtime.getRuntime();
        long usedBefore = rt.totalMemory() - rt.freeMemory();
        for (int i = 0; i < array.length; i++ ) {
            array[i] = new Object();
        }
        long usedAfter = rt.totalMemory() - rt.freeMemory();
        System.out.println(usedBefore);
        System.out.println(usedAfter);
        System.out.println((double)(usedAfter - usedBefore) / array.length);
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 一旦加载了一个类,该类本身就永远不会被垃圾回收

尽管Java语言规范没有对此进行强制性规定,但我曾经使用的每个JVM在其ClassLoader变得不可访问时都会释放一个类(当然,引导类加载器将始终保持可访问性,但是自定义ClassLoader可能会变得不可访问)。