- 浏览: 939861 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
hw7777777:
非常感谢作者提供这么好的工具,在使用的过程中遇到一些问题?1、 ...
基于java nio的memcached客户端——xmemcached -
SINCE1978:
多久过去了时间能抹平一切
无路用的人 -
fangruanyjq:
[img][/img]引用
用osworkflow写一个请假例子(提供代码下载) -
thinkingmysky:
楼主,你确定,java memached client能处理并 ...
memcached java client性能测试的几点疑问和说明 -
hellostory:
aaa5131421 写道07年2月hibernate已经出来 ...
dozer与BeanUtils
In the JVM, memory is allocated in two regions:
- Stack: Where local variables (declared in methods and constructors) are allocated. Local variables are allocated when a method is invoked and de-allocated when the method is exited.
- Heap: Where all objects created with the
new
keyword are allocated. Since local variables are few in number, only primitive types and references, usually the stack will not overflow, except in cases of unusually deep or infinite recursion. The JVM throws a Java out-of-memory error if it is not able to get more memory in the heap to allocate more Java objects. The JVM cannot allocate more objects if the heap is full of live objects and unable to expand further.
Causes of memory leaks in Java
The four typical causes of memory leaks in a Java program are:
- Unknown or unwanted object references: These objects are no longer needed, but the garbage collector can not reclaim the memory because another object still refers to it. Long-living (static) objects: These objects stay in the memory for the application's full lifetime. Objects tagged to the session may also have the same lifetime as the session, which is created per user and remains until the user logs out of the application. Failure to clean up or free native system resources: Native system resources are resources allocated by a function external to Java, typically native code written in C or C++. Java Native Interface (JNI) APIs are used to embed native libraries/code into Java code.
- Bugs in the JDK or third-party libraries: Bugs in various versions of the JDK or in the Abstract Window Toolkit and Swing packages can cause memory leaks.
Detection of memory leaks
Some approaches to detecting memory leaks follow in the list below:
- Use
the operating system process monitor, which tells how much memory a
process is using. On Microsoft Windows, the task manager can show
memory usage when a Java program is running. This mechanism gives a
coarse-grained idea of a process's total memory utilization. Use the
totalMemory()
andfreeMemory()
methods in the Java runtime class, which shows how much total heap memory is being controlled by the JVM, along with how much is not in use at a particular time. This mechanism can provide the heap's memory utilization. However, details of the heap utilization indicating the objects in the heap are not shown. - Use memory-profiling tools, e.g., JProbe Memory Debugger. These tools can provide a runtime picture of the heap and its utilization. However, they can be used only during development, not deployment, as they slow application performance considerably.
Causes of memory leaks in enterprise Java applications
In the subsequent sections, I analyze some causes of memory leaks in
enterprise Java applications using a sample application and a memory
profiling tool. I also suggest strategies for detecting and plugging
such leaks in your own projects. ResultSet and Statement Objects
The Statement
and ResultSet
interfaces are used with Java Database Connectivity (JDBC) APIs. Statement
/PreparedStatment
objects are used for executing a SQL Statement
; ResultSet
objects are used for storing SQL queries' results. A Java Enterprise
Edition (Java EE) application usually connects to the database by
either making a direct connection to the database using JDBC thin
drivers provided by the database vendor or creating a pool of database
connections within the Java EE container using the JDBC drivers. If the
application directly connects to the database, then on calling the close()
method on the connection object, the database connection closes and the associated Statement
and ResultSet
objects close and are garbage collected. If a connection pool is used,
a request to the database is made using one of the existing connections
in the pool. In this case, on calling close()
on the
connection object, the database connection returns to the pool. So
merely closing the connection does not automatically close the ResultSet
and Statement
objects. As a result, ResultSet
and Statement
will not become eligible for garbage collection, as they continue to
remain tagged with the database connection in the connection pool. To
investigate the memory leak caused by not closing Statement
and ResultSet
objects while using a connection pool, I used a sample Java EE
application that queries a database table and displays the results in a
JSP (JavaServer Pages) page. It also allows you to save records to the
database table. The application is deployed in iPlanet App Server 6.0.
I used JProbe to analyze the memory utilization by the application. The
sample application uses a database table with the following structure:
ID NUMBER
NAME VARCHAR2(300)
STREET VARCHAR(500)
CITY VARCHAR(500)
STATE VARCHAR(200)
CREATEDON DATE
VERSIONNO NUMBER
DELETESTATUS NUMBER
UPDATEDBY VARCHAR(20)
UPDATEDON DATE
First, I executed the application with the Statement
and ResultSet
objects closed. Subsequently, I executed the application by not closing the Statement
and ResultSet
objects. I did a query operation 50 times and observed the memory usage pattern. Scenario 1
The database table contains 100 rows and 10 columns. ResultSet
and Statement
objects are closed. The database connection is made using a connection
pool. The memory usage results of this scenario are shown in Figure 1.
Figure 1. When queried once, the heap memory usage increases by 166.308 KB. Click on thumbnail to view full-sized image. |
Figure 1 is a heap usage chart provided by JProbe. It gives a runtime summary of the heap memory in use over time as the Java EE application runs. The green area indicates the heap usage. The vertical line indicates a heap usage checkpoint has been set at that time. After setting the checkpoint, the query occurs and the heap memory usage shoots up as objects are created. Once the operation completes, the objects no longer referenced will be garbage collected by the JVM, so the memory usage decreases. Ideally at this time, all new objects should be released and garbage collected, and the heap usage should return to the value before the checkpoint was set. In this case, some new objects continue to occupy memory space, reflecting an increase in heap usage by 166.308 KB. When queried 10 times, the heap memory usage increases by 175.512 KB, as illustrated in Figure 2.
Figure 2. Ten queries. Click on thumbnail to view full-sized image. |
When queried 50 times, the heap memory usage increases by 194.128 KB, as shown in Figure 3.
Figure 3. Fifty queries. Click on thumbnail to view full-sized image. |
The observed increase in memory was traced to the connection objects stored in the pool for subsequent reuse. Scenario 2
The database table contains 100 rows and 10 columns. ResultSet
and Statement
objects are not
closed. The database connection is made using a connection pool. When
queried once, the heap memory usage increases by 187.356 KB, as shown
in Figure 4.
Figure 4. Results from one query. Click on thumbnail to view full-sized image. |
When queried 10 times, the heap memory usage increases by 217.016 KB.
Figure 5. Ten queries. Click on thumbnail to view full-sized image. |
When queried 50 times, the heap memory usage increases by 425.404 KB
Figure 6. Fifty queries. Click on thumbnail to view full-sized image. |
The difference in memory usage after 50 queries with open ResultSet
and Statement
objects is 231.276 KB. These results show that over time, these objects will cause a huge memory leak, thereby generating an OutOfMemoryError
.
In addition to the heap usage chart, JProbe also provides a runtime
view of class instances in the heap. From the class instance summary,
we can identify the objects present in the heap at any point in time.
Figure 7 shows a part of the class instance view of Scenario 2.
Figure 7. Class instance summary. Click on thumbnail to view full-sized image. |
Figure 7 clearly shows that 50 objects of OracleStatement
, 500 objects of DBColumn
,
etc., exist in the heap and are not garbage collected. JProbe provides
a reference/referrer tree for each class instance in the table, shown
in Figure 8. From this tree we can identify how each class instance was
created.
Figure 8. Referrer tree for the DBColumn object |
From the referrer tree of DBColumn
, we can see that it is created by the OracleStatement
object. The class oracle.jdbc.driver.OracleStatement
is the implementation for the Statement
interface. So by closing the Statement
object, all associated DBColumn
objects will be garbage collected. Recommendation
When using connection pools, and when calling close()
on the connection object, the connection returns to the pool for reuse.
It doesn't actually close the connection. Thus, the associated Statement
and ResultSet
objects remain in the memory. Hence, JDBC Statement
and ResultSet
objects must be explicitly closed in a finally block. Collection objects
A collection is an object that organizes references to other objects.
The collection itself has a long lifetime, but the elements in the
collection do not. Hence, a memory leak will result if items are not
removed from the collection when they are no longer needed. Java
provides the Collection
interface and implementation classes of this interface such as ArrayList
and Vector
. Using the same Java EE application tested in the previous scenario, I added the database query results to an ArrayList
. When 35,000 rows were present in the database table, the application server threw a java.lang.OutOfMemoryError
, with a default JVM heap size of 64 MB.
Figure 9. Heap summary when JVM throws java.lang.OutOfMemoryError. Click on thumbnail to view full-sized image. |
A collection with no policy for removing data causes a memory leak, known as the Leak Collection anti-pattern (read J2EE Design Patterns, for more information on anti-patterns). Recommendation
When collections are used, the object references stored in the
collections should be programmatically cleaned to ensure that the
collection size does not grow indefinitely. If the collection is being
used to store a large table's query results, data access should be
completed in batches. Static variables and classes
In Java, usually a class member (variable or method) is accessed in
conjunction with an object of its class. In the case of static
variables and methods, it is possible to use a class member without
creating an instance of its class. A class with static members is known
as a static class. In such cases, before a class instance is created,
an object of its class will also be created by the JVM. The class
object is allocated to the heap itself. The primordial class loader
will load the class object. In the case of static classes, all the
static members will also be instantiated along with the class object.
Once the variable is initialized with data (typically an object), the
variable remains in memory as long as the class that defines it stays
in memory. If the primordial class loader loads class instances, they
will stay in memory for the duration of the program and are not
eligible for garbage collection. So static classes and associated
static variables will never be garbage collected. Thus, using too many
static variables leads to memory leaks. Recommendation
Usage of static classes should be minimized as they stay in memory for the lifetime of the application. The Singleton pattern
The Singleton
pattern is an object-oriented design pattern used to ensure that a
class has only one instance and provide a global point of access to
that instance. The Singleton pattern can be implemented by doing the
following:
- Implementing a static method that returns an instance of the class Making the constructor private so a class instance can be created only through the static method
- Using a static variable to store the class instance
Example code for the Singleton pattern follows:
public class Singleton {
private static Singleton singleton=null;
private singleton () {
}
public static Singleton getInstace() {
if (singleton != null)
singleton=new Singleton();
return singleton;
}
}
The Singleton
class is typically used as a factory to create objects. I cached these objects into an ArrayList
to enable their speedy retrieval. When a new object must be created, it
will be retrieved from the cache if it is present there, otherwise, a
new object will be created.
Figure 10. Singleton class diagram. Click on thumbnail to view full-sized image. |
Once the Singleton
class is instantiated, it remains in memory for the application's
lifetime. The other objects will also have a live reference to it and,
as a result, will never be garbage collected. Recommendation
Avoid referencing objects from long-lasting objects. If such usage cannot be avoided, use a weak reference, a type of object reference that does not prevent the object from being garbage collected. HttpSession vs. HttpRequest
HTTP is a request-response-based stateless protocol. If a client wants
to send information to the server, it can be stored in an HttpRequest
object. But that HttpRequest
object will be available only for a single transaction. The HTTP server
has no way to determine whether a series of requests came from the same
client or from different clients. The HttpSession
object
is generally used to store data required from the time a user logs into
the system until he logs out. It brings statefulness into a
transaction. The session can be used for storing information such as a
user's security permissions. But often, programmers mistakenly store
complex long-living data, such as a shopping cart, into the session,
instead of using the business tier. I experimented with the sample
application to find the difference in memory usage between the HttpSession
and HttpRequest
objects since data stored in HttpSession
will stay in memory until the user logs out of the application. I added the database table's query results to an ArrayList
, which I then placed into both the HttpSession
and HttpRequest
objects. Memory usage was observed for 50 query-and-save operations. Scenario 1
The database table contains 100 rows. The output ArrayList
is stored in the HttpRequest
object to be passed back to the JSP page. After performing one
query-and-save operation, the increase in memory usage is 166.308 KB.
Figure 11. Results for one query-and-save operation. Click on thumbnail to view full-sized image. |
After completing 10 query-and-save operations, the increase in memory usage is 175.512 KB.
Figure 12. Ten operations. Click on thumbnail to view full-sized image. |
After performing 50 query-and-save operations, the increase in memory usage is 194.128 KB.
Figure 13. Fifty query-and-save operations. Click on thumbnail to view full-sized image. |
Scenario 2
The database table contains 100 rows. The output ArrayList
is stored in the HttpSession
object to be passed back to the JSP page. After one query-and-save operation, the increase in memory usage is 176.708 KB.
Figure 14. One query-and-save operation. Click on thumbnail to view full-sized image. |
After 10 query-and-save operations, the increase in memory usage is 178.46 KB.
Figure 15. Ten operations. Click on thumbnail to view full-sized image. |
After 50 query-and-save operations, the increase in memory usage is 216.552 KB.
Figure 16. Fifty operations. Click on thumbnail to view full-sized image. |
When the data is stored in HttpSession
, instead of HttpRequest
,
50 save-and-query operations increase memory usage by 22.424 KB. This
happens on a per client basis. Hence for multiple clients, the
multiplicative factor comes in as well. Over a period of time, this
will definitely lead to a significant memory leak in the application.
The data stored in HttpSession
stays in memory as long as the user is logged in. Putting too much data into HttpSession
leads to the Overstuffed Session anti-pattern. Since HttpSession
is implemented as a collection, this overstuffed session can be considered a variant of the Leak Collection anti-pattern. Recommendation
- Use of
HttpSession
s should be minimized and used only for state that cannot realistically be kept on the request object Remove objects fromHttpSession
if they are no longer used - Long-living data should be migrated to the business tier
Conclusion
I have highlighted some of the important programming scenarios where
the JVM's garbage collection mechanism becomes ineffective. These
situations necessitate appropriate precautions during design of the
application itself. While closing ResultSet
s and Statement
s
can be done after application development with comparatively low costs,
other aspects that I have explained get deeply embedded in the design
and could prove costly to correct. The garbage collector is a
low-priority thread. Hence in a heavily loaded Java EE application,
garbage collection itself may happen infrequently. Even those objects
that could have been potentially garbage collected may actually stay in
memory for a long time. So explicitly cleaning the heap may be a
mandatory programming requirement in some applications; doing so must
be considered on a case-by-case basis.
|
Printer-friendly version | Mail this to a friendAbout the author
Ambily Pankajakshan
works as a scientist in the Centre for Artificial Intelligence and
Robotics. She has more than five years of experience in the design and
development of multitiered Java EE applications. Her areas of interests
are performance-tuning Java EE applications and application servers.
She holds a B.Tech Degree in computer science and engineering from M.G.
University, Kerala India. Currently, she lives in Bangalore with her
husband Nishore and son Ananthu.
- Resources
- JVM specification:
http://java.sun.com/docs/books/vmspec
Download JProbe Memory Debugger:
http://www.quest.com/jprobe/debugger.asp
J2EE Design Patterns, by William C. R. Crawford and Jonathan Kaplan (O'Reilly, September 2003; ISBN: 0596004273) is a good book on J2EE design patterns and anti-patterns:
http://www.amazon.com/exec/obidos/ASIN/0596004273/javaworld
Learn more about weak references: "Reference Objects and Garbage Collection," Monica Pawlan (Sun Developer Network, August 1998):
http://java.sun.com/developer/technicalArticles/ALT/RefObj - For more on the Singleton pattern, read "Simply Singleton," David Geary (JavaWorld, April 2003):
http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html? - For the basics on garbage collection, read JavaWorld's "Trash Talk" series from Jeff Friesen:
- Part 1: Java recycles its memory through garbage collection (December 2001):
http://www.javaworld.com/javaworld/jw-12-2001/jw-1207-java101.html Part 2: The Reference Objects API allows programs to interact with the garbage collector (January 2002):
http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-java101.html?
http://www.javaworld.com/channel_content/jw-jvm-index.shtml
For more articles on design patterns, browse the Design Patterns section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-patterns-index.shtml - Part 1: Java recycles its memory through garbage collection (December 2001):
- For more articles on Java EE, browse the Java Enterprise Edition section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-j2ee-index.shtml?
发表评论
-
memcached分布测试报告(一致性哈希情况下的散列函数选择)
2009-03-10 16:30 8544一、背景资料 memcached本身是集中式的缓存系统 ... -
xmemcached 0.60 优化过程
2009-03-06 14:37 3521充分利用jprofile等 ... -
Xmemcached vs Spymemcached 3th(linux下测试结果和多节点下表现)
2009-03-07 10:43 4881翠花,上图,首先是容器类和自定义对象的get、set在不同并发 ... -
xmemcached发布1.0-BETA版
2009-03-09 15:32 4119xmemcached 发布1.0-beta ,从0.6 ... -
山寨nio框架yanf4j发布0.50-alpha
2009-02-04 19:28 4221俺的山寨nio框架yanf4j发布0.50-alpha版本,下 ... -
yanf4j引入了客户端非阻塞API
2009-02-19 00:15 3116yanf4j 发布一个0.50-beta2 版本,这个版本最 ... -
基于java nio的memcached客户端——xmemcached
2009-03-03 16:31 74741、xmemcached是什么? xmemcached是基于 ... -
使用yanf4j写个简单聊天室
2008-11-26 11:36 5397yanf4j 简介,请看这里 ... -
Java字符串的最大长度
2009-01-15 01:37 7585在cpp中为了可移植性,s ... -
yanf4j-0.41 beta发布
2009-01-20 14:01 1866项目名称:yanf4j (yet another nio fr ... -
再谈Selector的wakeup方法
2009-02-01 11:15 3051过去推荐过两篇blog《Java NIO类库Selector机 ... -
Yet another nio framework for java
2008-10-11 14:25 2046项目名称:Yanf4j(Yet another nio fra ... -
阻塞队列的性能对比
2008-09-08 10:06 5745阻塞队列的性能对 ... -
java package的设计原则
2008-09-06 00:15 2118典型的J2EE项目,package的设计有成熟的套路可 ... -
线程池池
2008-09-01 19:39 1998这个题目比较怪,听俺道来。俺一直在负责公司游戏服 ... -
第一个MapReduce任务
2008-08-23 11:10 2783前两天在公司内网上搭了个2个节点hadoop集群, ... -
从HDFS看分布式文件系统的设计需求
2008-08-15 22:39 8119分布式文件系统的 ... -
HDFS用户指南(翻译)
2008-08-14 20:27 2141HDFS用户指南 原文地址:http:/ ... -
Ehcache配置的overflowToDisk属性
2008-08-06 23:18 10838Ehcache的overflowToDisk属性用来配 ... -
工作的几个tip
2008-07-07 20:47 28851、如果用java6的ScriptEngineManager ...
相关推荐
### Detected Memory Leaks 简单检测方法 #### 背景介绍 在软件开发过程中,内存泄漏是一个常见的问题,特别是在使用C/C++等需要手动管理内存的语言进行开发时更为突出。内存泄漏不仅会导致程序占用的内存持续增长...
iOS应用隐私泄露检测知识点: iOS应用隐私泄露检测是指对运行在苹果iOS操作系统上的应用进行审查,以发现它们是否将用户设备上的敏感信息泄露给第三方。随着智能手机的普及,特别是苹果公司的iOS和谷歌公司的...
### 消除Symbian OS C++项目中的内存泄漏 #### 概述 在Symbian OS中,内存管理是一项至关重要的任务,特别是在C++项目中。本文将深入探讨如何在Symbian OS环境中检测、避免内存泄漏,并提供具体方法来解决这些问题...
标题《论文研究-A Tool for Testing Java Memory Leaks.pdf》和描述《一个测试Java内存泄漏的工具,党万春,钱巨,虽然Java语言有自带的垃圾回收机制,Java程序仍然存在由无效引用带来的内存泄漏。而内存泄漏会导致...
### Java内存泄漏详解 #### 摘要 本文旨在探讨如何在IBM WebSphere Application Server (WAS) 3.5、4.01 和 5.0 版本上诊断和定位 Java 内存泄漏问题,包括分布式环境和 z/OS 环境。文章将介绍一种通用的方法论,...
这篇“Finding memory leaks发现内存的泄漏”可能是关于如何定位和解决内存泄漏的技术指南。 在C++编程中,程序员需要手动管理内存,通过`new`关键字申请内存,然后通过`delete`关键字释放内存。如果忘记释放或错误...
标题 "How catch memory leaks with very little effort (7KB)" 提示了这是一个关于如何轻松检测内存泄漏的技术分享。内存泄漏是编程中的一个常见问题,尤其是在C++等不自动管理内存的语言中,程序员需要手动分配和...
文章《Detecting Passive Content Leaks and Pollution in Android Applications》主要探讨了在Android应用程序中两个关键的安全漏洞,这些漏洞都与Android的一个不受保护的组件ContentProvider有关。由于缺少必要的...
平常我们都会用 Instrument 的 Leaks / Allocations 或其他一些开源库进行内存泄露的排查,但是检查过程非常繁琐,而且不清晰,最主要的是Abandoned memory不会被检测出来。 Leaks 从苹果的开发者文档里可以看到,一...
You will begin with a basic understanding of memory management, and why memory leaks occur in an application, moving on to autorelease pools and object creation/storage to get an idea of how memory ...
在压缩包中的文件,如`memory_leaks.shtml.htm`,可能包含了更详细的内存泄漏检测和解决方法。`VC Empire.htm`可能涉及到在Visual C++环境中如何处理内存泄漏的问题。阅读这些文件可以获取更多实用技巧和案例分析。 ...
ANTS Memory Profiler icon ANTS Memory Profiler: Find and fix memory leaks in your .NET applications. Exception Hunter icon Exception Hunter: Locate the unhandled exceptions your method can throw.
- fixed memory leaks in font packing subsystem + Added Embarcadero RAD Studio XE5 support + Added Internal components for FireDac database engine + fixed bug with images in PDF export for OSX viewers ...
- fixed memory leaks in font packing subsystem + Added Embarcadero RAD Studio XE5 support + Added Internal components for FireDac database engine + fixed bug with images in PDF export for OSX ...
- fixed memory leaks in font packing subsystem + Added Embarcadero RAD Studio XE5 support + Added Internal components for FireDac database engine + fixed bug with images in PDF export for OSX viewers ...
- fixed memory leaks in font packing subsystem + Added Embarcadero RAD Studio XE5 support + Added Internal components for FireDac database engine + fixed bug with images in PDF export for OSX viewers ...
- fixed memory leaks in font packing subsystem + Added Embarcadero RAD Studio XE5 support + Added Internal components for FireDac database engine + fixed bug with images in PDF export for OSX viewers ...
- fixed memory leaks in font packing subsystem + Added Embarcadero RAD Studio XE5 support + Added Internal components for FireDac database engine + fixed bug with images in PDF export for OSX ...
为了有效地排查和解决这类问题,开发者通常会借助专业工具,而“Java内存泄漏排除工具MAT”(Memory Analyzer Tool)就是一个强大的诊断工具。MAT是由Eclipse基金会开发的,用于分析Hprof格式的堆转储文件,帮助...
内存泄漏是程序运行过程中的常见问题,特别是在C和C++这样的低级编程语言中,由于程序员需要手动管理内存,不正确的内存分配和释放可能导致内存泄漏。`__wrap_malloc`是一种调试技术,用于检测由`malloc()`函数引起...