Java是一种伟大的语言。它管理内存,传授面向对象的编程(思想),使我们更好地用它来编码。另外,它确实是一种“编写一次,到处运行“的语言。然而,Java应用程会遇到一些常见的开发者和应用者独耳熟能详的性能挑战。

内存泄露

  Java的最大的好处之一是它能够管理内存模型。当对象不再使用时,Java会做清理工作。较旧的语言需要人工来管理内存,但开发者宁愿花时间专注于核心语言逻辑而不愿为内存分配而忧心。

  话虽如此,却不能保证Java的内存管理没有问题,提供管理内存模型,或创建/销毁未使用的对象,(这些对象)都放在Java的“堆(Heap)“中,内存泄露通常是不正确编程的结果–通常,开发者没有消除某一对象的所有引用,因此,堆(空间)逐步耗尽,应用程序也将死机。

  大多数人使用堆转储和/或事件探查器(profiler)来诊断内存泄漏。堆转储使你可看到哪个对象持有对集合的引用。它告诉你集合何处,但不能告诉你谁在存取该集合或其它能让你探究根源的特性。堆转储通常占用的空间也相当大,在千兆字节,分析并打开一个堆转储需要大量资源,然后读取它,并找出问题所在。

  第二种方法,是组合堆转储和事件探查器,使你能接近点问题本质,但并不多。内存分析器尽力帮助您分析您的堆转储。他们有实时数据,现在可知道是谁创建的对象,但仍不知造成泄漏的真正根由。

  堆转储和分析器都有益于开发和预生产,然而,一旦应用程序失控,分析器也不可用。隔离并解决内存泄漏最有效的方法来之一是通过事务(transaction)(管理)和代码路径分析。通过采取事务快照,可以获得问题所在及其原因,这通常会导致更少的停机时间和更好的MTTR。

缓慢的SQL

  几乎每一应用程序都会使用JDBC数据库。应用中一个非常普遍的问题是糟糕的SQL的性能,这可有时由于字段未创建索引、获取的数据量太多或者其他原因所致。这会不利于应用的性能,因为大多数应用程序在每一应用请求中涉及很多SQL调用。

 可能有很多造成SQL执行缓慢的原因,但是其中之一特别突出:对象-关系映射(ORM)。

  ORM以成为将当今两大业务应用基础技术(面向对象的应用(Java、.NET)和关系数据库(Oracle、MySQL和PostgreSQL等))整合在一起的首选方法。今天的大多数应用采用关系数据库,对于许多开发人员而言,(ORM)这项技术可以消除需要升入探讨着两种技术如何相互作用的复杂度。然而,ORM使得应用需承受额外的负担,并极大地影响应用的性能,而一切表面上看起来很好。

  在大多数情况下,检索数据所消耗的时间和占用资源的数量级远大于数据处理所需的时间及资源,因此,性能方面的考虑常包含访问和存储数据的工具和方法就不足为奇了。

  虽然开发人员直观地使用(隐藏复杂性),但ORM在应用性能方面应占据很大的比重,以确保(开发人员)明白问题的实质。

 线程/同步

  由同步所产生的问题往往很难辨认,但是其对性能的影响却非常显著。

  对同步的最根本的需要在于Java对并发的支持,这通过在相同的过程中执行不同的线程(thread)代码来实现。单独的线程之间可以共享相同的资源,以及内存中的对象。虽然是一种完成更多工作的有效方法(当以线程在等待I/O操作完成期间,另一线程可利用CPU来进行计算),但是也曝露出应用的干扰和一致性问题。

  为防止这种情况,程序员在程序中引入“synchronized”关键字来强制并发线程的执行顺序。利用“synchronized”来防止线程在同一时间获得同一资源,并防止数据不一致。

  然而在实践中,这个简单的机制却带来很大的副作用。现代企业的应用常采用多线程的实现模式,同时执行多个线程,对“共享”对象的争夺也随之加剧,同步将有效地强制并发处理转而为顺序执行。

  目前,对于线程和同步问题没有银弹(silver bullet)。某些开发者依赖“防御”性编程方法,诸如加锁;而另一些开发者,则依赖STM(Software Transactional Memory Systems)来缓解这个问题。最好的开发组织是那些可以平衡代码审查/重写负担和性能问题的团队。

  这些只是Java开发人员每天必须面对的应用性能问题,有许多有用的性能工作可以大大减少此类问题。