字符串有问题
基本上在 Java 中,引用(在幕后String
使用的东西)将主导大多数业务应用程序的内存。它们的创建方式决定了它们在 JVM 中消耗的内存量。char[]
仅仅因为它们作为一种数据类型对于大多数业务应用程序来说都是如此重要,而且它们也是最需要内存的类型之一。这不仅仅是 Java 的事情,String
几乎每种语言和运行时库中的数据类型都会占用大量内存,因为至少它们只是每个字符 1 个字节的数组,或者更糟糕的是(Unicode)它们是每个字符多个字节。
有一次,在对同样具有 Oracle JDBC 依赖项的 Web 应用程序的 CPU 使用情况进行分析时,我发现它比所有其他方法调用组合StringBuffer.append()
的 CPU 周期占主导地位许多数量级,更不用说任何其他单个方法调用了。JDBC 驱动程序做了很多很多的操作,有点像使用所有东西的权衡。String
PreparedStatements
你所关心的你无法控制,反正不是直接
您应该关注的是您可以控制的内容,这确保您不会保留比您需要的时间更长的引用,并且您不会不必要地重复事物。Java 中的垃圾收集例程经过高度优化,如果您了解它们的算法是如何工作的,就可以确保您的程序以最佳方式运行,以使这些算法能够正常工作。
Java 堆内存不像其他语言中的手动管理内存,这些规则不适用
在其他语言中被认为是内存泄漏的事情/根本原因与 Java 中的垃圾收集系统不同。
在 Java 中,内存很可能不会被一个正在泄漏的 uber-object 消耗(其他环境中的悬空引用)。
StringBuffer
由于/StringBuilder
对象在第一次实例化时大小不合适,因此很可能有很多较小的分配,然后必须自动增长char[]
数组以保存后续append()
调用。
由于它们所处的范围以及在运行时可能会发生变化的许多其他因素,这些中间对象可能会比垃圾收集器预期的更长。
示例:垃圾收集器可能会确定有候选者,但因为它认为还有大量内存可用,所以在那个时间点将它们刷新出来可能过于昂贵,它会等到内存压力越来越大。
垃圾收集器现在真的很好,但它不是魔法,如果你在做退化的事情,它会导致它不能以最佳方式工作。互联网上有很多关于所有 JVM 版本的垃圾收集器设置的文档。
这些未引用的对象可能只是没有达到垃圾收集器认为需要它们才能从内存中清除它们的时间,或者可能存在对它们的引用由其他对象(List
)持有,例如你不实现仍然指向该对象。这就是 Java 中最常见的泄漏,更具体地讲是引用泄漏。
示例:如果您知道需要String
使用StringBuilder
创建它而new StringBuilder(4096);
不是默认值(例如 32)来构建 4K,并且将立即开始创建垃圾,这些垃圾可以代表您认为对象大小的许多倍。
您可以发现使用 VisualVM 实例化了多少类型的对象,这将告诉您您需要了解的内容。不会有一个大的闪光灯指向单个类的单个实例,说“这是大内存消耗者!”,除非只有一个实例char[]
你正在阅读一些大量的文件到,这也是不可能的,因为许多其他类在char[]
内部使用;然后你几乎已经知道了。
我没有看到任何提及OutOfMemoryError
您的代码可能没有问题,垃圾收集系统可能没有承受足够的压力来启动和释放您认为应该清理的对象。您认为的问题可能不是,除非您的程序因OutOfMemoryError
. 这不是 C、C++、Objective-C 或任何其他手动内存管理语言/运行时。您无法以您期望的详细程度来决定内存中的内容。