时不时地会有一个垂死的生产应用程序。 而且您知道您需要尽快对其进行修补。 我们也一样,并认为分享最近的一个战争故事将很有趣。 在这种情况下,我们就有机会使用String.intern()之类的简单补丁来修补应用程序。 但是,让我从头开始。
当前的应用程序正遭受内存不足的困扰,甚至在最近的更改后都无法启动。 症状包括JVM重新启动后CPU使用率过高,然后几分钟后出现致命的OutOfMemoryError:日志中的堆空间 。 快速查看堆内容使我们产生了疑问-应用程序正在将数百万个对象加载到某个内部数据结构中。
与开发团队进行的背景调查显示,最近加载的对象数量乘以两倍-而不是大约500万个对象,应用程序现在必须处理大约一千万个内存实例。 实际上,这可能会占用一些堆空间。 但是,知道可能的原因并不会给我们带来太大帮助-企业主绝不愿意放弃他们刚刚获取的宝贵数据。
深入研究手头的数据结构,我们发现其在下面过度使用了字符串。 对于我们的任何读者来说,这都不奇怪。 但是其中一些字符串包含重复的表示内容。 您可以将地址元素(例如街道名称和/或国家/地区)视为等效的情况。
快速解决方案开始在我们的脑海中酝酿。 如果我们内部化那些重复的字符串怎么办? 与应用程序的开发人员Swift核实之后,我们获得了绿灯。 开发人员保证,将包含实习的副作用,例如记住String.intern()与我们内部化的Strings进行比较的所有字符串。 感谢上帝的封装。
现在我们只需要了解内部化要引入多少CPU开销。 令我们惊讶的是,实习到大约1000万个琴弦只花了不到四分钟的时间。 并为我们节省了大约不足的500MB内存。 因此,节省了时间。
现在,在您跳至应用程序并开始内部化将要查找的所有Strings之前,我必须事先警告您。 有很多可能出错的地方:
- 您内部化的字符串将从堆中消失,并重新定位到永久代。 因此,请确保您在permgen空间中有足够的空间。
- 确保将要与内部化的字符串进行比较的所有字符串内部化。 否则,您将在应用程序中创建最讨厌的错误类型。
- 确保可以忍受内部化时的CPU开销。 这是一个本机方法调用,因此它将完全取决于您的特定平台,因此请确保在进行生产更改之前尝试一下
我们承认这种情况很少见–数据结构包含许多重复的String对象,并以一种使我们能够隔离快速修复的方式与应用程序集成。 甚至在我们的情况下,该修复程序很快也被开发人员删除,他们将数据结构重新设计为更合理的图形表示形式。
但是除了警告-Java虚拟机中内置了有趣且有用的工具。 知道如何使用它们,并提防它们的副作用,它们将成为您的朋友。 谨慎使用它们,您可以轻松终止应用程序。 您最好的朋友将永远是一个基于您自己的应用程序构建的实际测试用例。
翻译自: https://www.javacodegeeks.com/2013/06/reducing-memory-usage-with-string-intern.html