Java平台最突出的功能之一是其自动内存管理。 许多人错误地将此功能转换为Java中没有内存泄漏 。 但是,事实并非如此,我给人的印象是,现代Java框架和基于Java的平台,尤其是Android平台,越来越与这种错误的假设相矛盾。 为了对Java平台上的内存泄漏如何产生印象,请查看以下堆栈实现:

class SimpleStack {private final Object[] objectPool = new Object[10];private int pointer = -1;public Object pop() {if(pointer < 0) {throw new IllegalStateException("no elements on stack");}return objectPool[pointer--];}public Object peek() {if(pointer < 0) {throw new IllegalStateException("no elements on stack");}return objectPool[pointer];}public void push(Object object) {if(pointer > 8) {throw new IllegalStateException("stack overflow");}objectPool[++pointer] = object;}
}

此堆栈实现以数组形式存储其内容,并另外管理一个指向当前活动堆栈单元的整数。 每当元素从堆栈顶部弹出时,此实现都会导致内存泄漏。 更准确地说,堆栈将保留对数组顶部元素的引用,即使不再使用它也是如此。 (除非再次将其压入堆栈,否则将导致引用被完全相同的引用覆盖。)因此,即使在释放了对该对象的所有其他引用之后,Java也将无法对其进行垃圾回收。 由于堆栈实现不允许直接访问基础对象池,因此,在将新元素推入堆栈的相同索引之前,此不可访问的引用将阻止对引用对象进行垃圾回收。

幸运的是,这种内存泄漏很容易解决:

public Object pop() {if(pointer < 1) {throw new IllegalStateException("no elements on stack");}try {return objectPool[pointer];} finally {objectPool[pointer--] = null;}}

当然,在日常Java开发中,内存结构的实现并不是一项非常常见的任务。 因此,让我们看一个更常见的Java内存泄漏示例。 这种泄漏通常是由常用的观察者模式引起的 :

class Observed {public interface Observer {void update();}private Collection<Observer> observers = new HashSet<Observer>();void addListener(Observer observer) {observers.add(observer);}void removeListener(Observer observer) {observers.remove(observer);}}

这次,存在一种允许直接从基础对象池中删除引用的方法。 只要任何已注册的观察者在使用后都从外部取消注册,就不会在此实现中担心任何内存泄漏。 但是,请设想一个场景,在这种情况下,您或框架的用户在使用观察器后会忘记注销注册。 同样,观察者将永远不会被垃圾回收,因为观察者会一直引用它。 更糟糕的是,如果没有对这个现在无用的观察者的引用,就不可能从外部从观察者的对象池中删除观察者。

但是,这种潜在的内存泄漏也很容易解决,其中涉及使用弱引用 ,这是我个人希望程序员会更加意识到的Java平台功能。 简而言之,弱引用的行为类似于普通引用,但不会阻止垃圾回收。 因此,如果没有剩余的强引用,并且JVM执行了垃圾回收,则可以突然发现弱引用为null。 使用弱引用,我们可以像这样更改上面的代码:

private Collection<Observer> observers = Collections.newSetFromMap(new WeakHashMap<Observer, Boolean>());

WeakHashMap是地图的现成实现,使用弱引用包装其键。 通过此更改,被观察者将不会阻止其观察者进行垃圾收集。 但是,您应该始终在Java文档中指出此行为! 如果您的代码用户想要像日志实用程序一样向您的观察者注册永久观察者,而他们不打算对其进行引用,则可能会造成很大的混乱。 例如,Android的OnSharedPreferencesChangeListener使用弱引用来监听,而没有记录此功能。 这可以让您彻夜难眠!

在本博客文章的开头,我建议当今的许多框架都需要其用户进行仔细的内存管理,并且我想就该主题至少给出两个示例来解释这一问题。

Android平台:

Android编程为核心应用程序类引入了生命周期编程模型。 总而言之,这意味着您无法控制自己创建和管理这些类的对象实例,而是可以在需要时由Android OS为您创建它们。 (例如,如果您的应用程序应该显示特定的屏幕。)以同样的方式,Android将决定何时不再需要特定的实例(例如,当用户关闭应用程序的屏幕时),并通知您有关信息。通过在实例上调用特定的生命周期方法进行删除。 但是,如果让对该对象的引用进入某些全局上下文,则Android JVM将无法按照其意图进行垃圾回收。 由于Android手机通常在内存方面受到限制,并且因为Android的对象创建和销毁例程甚至对于简单的应用程序都可能变得非常疯狂,因此您必须格外小心以清理引用。

不幸的是,对核心应用程序类的引用很容易消失。 在下面的示例中,您可以发现滑动参考吗?

class ExampleActivity extends Activity {@Overridepublic void onCreate(Bundle bundle) {startService(new Intent(this, ExampleService.class).putExtra("mykey",new Serializable() {public String getInfo() {return "myinfo";}}));}
}

如果您认为这是intent的构造函数中的this引用,那您是错误的。 该意图仅用作服务的启动命令,并且在服务启动后将被删除。 取而代之的是,匿名内部类将保留对其封闭类的引用,即ExampleActivity类。 如果接收的ExampleService保留对该匿名类的实例的引用,则结果还将保留对ExampleActivity实例的引用。 因此,我只能建议Android开发人员避免使用匿名类。

Web应用程序框架(特别是

Web应用程序框架通常在会话中存储半永久性用户数据。 无论您写入会话的什么内容,通常都会在内存中保留不确定的时间。 如果您在有大量访问者的情况下浪费了会话,则servlet容器的JVM迟早会打包。 Wicket框架是需要格外小心的一个极端示例:Wicket序列化用户以版本化状态访问的任何页面。 简单地说,这意味着如果网站的访问者之一单击您的欢迎页面十次,Wicket将以其默认配置在您的硬盘驱动器上存储十个序列化对象。 这需要格外小心,因为Wicket页面对象持有的所有引用都将导致这些引用对象与页面一起被序列化。 看一下这个不好的实践Wicket示例:

class ExampleWelcomePage extends WebPage {private final List<People> peopleList;public ExampleWelcomePage (PageParameters pageParameters) {peopleList = new Service().getWorldPhonebook();}
}

通过十次单击欢迎页面,您的用户仅将十本世界电话簿副本存储在服务器硬盘驱动器上。 因此,请始终在Wicket应用程序中使用LoadableDetachableModel ,它将为您提供参考管理。

跟踪Java应用程序中的内存泄漏可能很麻烦,因此,我想将JProfiler命名为有用的(但不幸的是非免费的)调试工具。 它允许您以堆转储的形式浏览Java正在运行的应用程序的内部。 如果内存泄漏对于您的应用程序来说是一个问题,我建议您尝试一下JProfiler。 有可用的评估许可证。

进一步的阅读 :如果要在自定义类加载器时看到另一个有趣的内存泄漏事件,请参阅Zeroturnaround博客 。

参考: My Daily Java博客上的JCG合作伙伴 Rafael Winterhalter提供了Java应用程序中的内存泄漏和内存管理 。

翻译自: https://www.javacodegeeks.com/2014/01/memory-leaks-and-memory-management-in-java-applications.html

Java应用程序中的内存泄漏和内存管理相关推荐

  1. 监视和检测Java应用程序中的内存泄漏

    因此,您的应用程序内存不足,您日夜不停地分析应用程序,以期捕获对象中的内存漏洞. 后续步骤将说明如何监视和检测您的内存泄漏,以确保您的应用程序安全. 1.怀疑内存泄漏 如果您怀疑有内存泄漏,可以使用一 ...

  2. java应用程序占用高内存_对Java应用程序中的内存问题进行故障排除

    java应用程序占用高内存 重要要点 解决内存问题可能很棘手,但是正确的方法和正确的工具集可以大大简化此过程. Java HotSpot JVM可以报告几种OutOfMemoryError消息,因此务 ...

  3. java 内存溢出 内存泄露_JVM——内存泄漏与内存溢出

    1.内存溢出 1.1 什么是Java的内存溢出? 在Java程序运行的过程中,经常会碰到以下错误:java.lang.OutOfMemoryError. 通俗讲,内存溢出是指程序在申请内存时,没有足够 ...

  4. java内存泄漏和内存溢出_Java和内存泄漏

    java内存泄漏和内存溢出 总览 术语"内存泄漏"在Java中的使用方式不同于在其他语言中使用的方式. 通用术语中的"内存泄漏"是什么意思,在Java中如何使用 ...

  5. 透彻分析JAVA内存泄漏和内存溢出的区别

    JAVA内存泄漏和内存溢出的区别和联系 1.内存泄漏memory leak : 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出. 2 ...

  6. java内存泄漏和内存溢出

    java内存泄漏和内存溢出 概念 a)内存泄露:被分配对象可达但无用 b)内存溢出:无法申请到足够的内存而产生的错误 内存泄漏场景 a)创建和应用生命周期一样的单例对象 b)创建匿名内部类的静态对象 ...

  7. C++中的内存管理、内存泄漏和内存回收

    C++中的内存分布 一.内存管理 1.C++内存管理详解 1.1.内存组成 1.2.堆与栈的区别 2.指针与数组 2.1.修改内容 2.2. 内容复制与比较 2.3. 计算内存容量 3. 有了mall ...

  8. JAVA内存泄漏和内存溢出的区别和联系

    内存泄漏和内存溢出的区别与解决方式_jie1175623465的博客-CSDN博客_内存泄露和内存溢出是指什么,它们有什么区别 内存泄漏(memory leak ) 内存溢出 (out of memo ...

  9. Linux启动检测内存条错误,linux检测程序内存泄漏和内存错误

    在linux的开发程序的时候,可以很方便的使用valgrind这个工具方便检测内存泄漏和内存错误. 安装很方便: debian(如ubuntu) sudo apt-get install valgri ...

最新文章

  1. insightface face_preprocess
  2. 需要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。
  3. CCF - 201703-1 - 分蛋糕
  4. mvn install java版本,maven的打包命令--assemblyinstall和maven update之后jdk版本变回1.5的问题...
  5. linux mongodb启动_linux运维服务篇:MongoDB部署教程分享
  6. 百度李彦宏:自动驾驶最后一公里率先到来;未来20年手机依赖会降低
  7. HIVE学习之(三)
  8. cmake使用介绍【转】
  9. 网易新闻 鸿蒙,网易新闻鸿蒙版下载-网易新闻 鸿蒙版v78.5-PC6鸿蒙网
  10. SpringCloud学习
  11. 恶意程序检测之malconv模型
  12. L1-8 雀魂majsoul (20 分)
  13. php zend guard php 7,zend guard php7最新版
  14. 微信拼手气红包背后的算法逻辑
  15. AI生成新春祝福海报,AIGC从“炫技”走向日常
  16. 你不得不会的EXCEL选择性粘贴
  17. Java SimpleDateFormat用法
  18. 互联网应用基础第一课:计算机的工作原理、了解计算机的硬件与系统
  19. 赋能千行百业,AI究竟走到哪一步了?
  20. python视频网站项目_Python Flask 项目实战—构建微电影视频网站

热门文章

  1. C++字符串分割替换 ubuntu版本
  2. 下载bilibli网站视频
  3. 分数优先遵循志愿php源码_分数优先 遵循志愿
  4. 微服务pact测试框架_消费者驱动的Pact和Spring Boot测试
  5. 敏捷中gwt含义_在GWT中序列化/反序列化Json
  6. antlr 语言 库_关于ANTLR的通用库的需求:使用反射来构建元模型
  7. java工程引入scala_引入ReactiveInflux:用于Scala和Java的无阻塞InfluxDB驱动程序,支持Apache Spark...
  8. 戴尔集群监控与管理系统_监控与管理
  9. java分割句子_关于Java的一些句子
  10. javafx ui_调用以验证JavaFX UI的响应能力