Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to plug memory leaks with weak references in Java

2025-04-10 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "how to plug memory leaks with weak references in Java". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to plug memory leaks with weak references in Java.

Although programs written in the Java ™language are theoretically free of "memory leaks", sometimes objects are not garbage collected after they are no longer part of the program's logical state. This month, Brian Goetz, an engineer responsible for ensuring application health, explored common reasons for unconscious object retention and showed how to plug leaks with weak references.

For an object that is no longer used by the garbage collection (GC) program, the logical life cycle of the object (when the application uses it) and the actual life cycle of references to the object must be the same. Most of the time, good software engineering techniques ensure that this is automated and that we don't have to pay too much attention to the lifecycle of objects. But occasionally we create a reference that contains objects in memory for much longer than we expected, a situation called unconscious object retention (unintentional object retention).

Memory leak caused by global Map

The most common reason for unconscious object retention is the use of Map to associate metadata with temporary objects (transient object). Assume that an object has a medium life cycle, which is longer than the method call that allocates it, but shorter than the life cycle of the application, such as the socket connection of the client. Some metadata needs to be associated with this socket, such as the identity of the user who made the connection. This information is not known when the Socket is created, and data cannot be added to the Socket object because you cannot control the Socket class or its subclasses. At this point, the typical approach is to store this information in a global Map, as shown in the SocketManager class in listing 1:

Listing 1. Use a global Map to associate metadata to an object

Public class SocketManager {

Private Map

M = new HashMap ()

Public void setUser (Socket s, User u) {

M.put (s, u)

}

Public User getUser (Socket s) {

Return m.get (s)

}

Public void removeUser (Socket s) {

M.remove (s)

}

}

SocketManager socketManager

...

SocketManager.setUser (socket, user)

The problem with this approach is that the life cycle of the metadata needs to be linked to the life cycle of the socket, but unless you know exactly when the socket is no longer needed by the program and remember to remove the corresponding mapping from the Map, the Socket and User objects will stay in the Map forever, far longer than responding to requests and closing the socket. This prevents Socket and User objects from being garbage collected, even if the application no longer uses them. These objects are left out of control, which can easily cause the program to be full of memory after running for a long time. Except in the simplest case, finding out when Socket is no longer used by programs in almost all cases is an annoying and error-prone task that requires manual memory management.

Find out about memory leaks

The first sign that a program has a memory leak is usually that it throws an OutOfMemoryError or shows poor performance due to frequent garbage collection. Fortunately, garbage collection can provide a great deal of information that can be used to diagnose memory leaks. If you call JVM with the-verbose:gc or-Xloggc option, each time GC runs, a diagnostic is printed on the console or in the log file, including the time it took, the current heap usage, and how much memory has been recovered. Recording GC usage is not intrusive, so it is worthwhile to enable GC logging by default in a production environment if you need to analyze memory problems or tune the garbage collector.

JTune is one such tool that can take advantage of GC log output and display it graphically (see Resources). Looking at the graph of heap size after GC, you can see the trend of program memory usage. For most programs, memory usage can be divided into two parts: baseline usage and current load usage. For server applications, baseline usage is the memory usage of the application when there is no load but is ready to accept requests. Current load usage is memory used during request processing, but is freed after request processing is completed. As long as the load is generally constant, the application usually reaches a stable level of memory usage very quickly. If memory usage continues to increase when the application has completed its initialization and the load does not increase, the program may retain the generated object when processing the previous request.

Listing 2 shows a program with a memory leak. MapLeaker processes tasks in a thread pool and records the status of each task in a Map. Unfortunately, it does not delete that item after the task is completed, so state items and task objects (and their internal states) continue to accumulate.

Listing 2. Programs with Map-based memory leaks

Public class MapLeaker {

Public ExecutorService exec = Executors.newFixedThreadPool (5)

Public MaptaskStatus

= Collections.synchronizedMap (new HashMap ())

Private Random random = new Random ()

Private enum TaskStatus {NOT_STARTED, STARTED, FINISHED}

Private class Task implements Runnable {

Private int [] numbers = new int [random.nextInt]

Public void run () {

Int [] temp = new int [random.nextInt (10000)]

TaskStatus.put (this, TaskStatus.STARTED)

DoSomeWork ()

TaskStatus.put (this, TaskStatus.FINISHED)

}

}

Public Task newTask () {

Task t = new Task ()

TaskStatus.put (t, TaskStatus.NOT_STARTED)

Exec.execute (t)

Return t

}

}

Once you are sure that there is a memory leak, the next step is to find out which object is causing the problem. All memory parsers can generate heap snapshots that are decomposed by object class. There are some good commercial heap analysis tools, but you don't have to pay for them to find memory leaks-- the built-in hprof tool can do the same. To use hprof and have it track memory usage, you need to call JVM with the-Xrunhprof:heap=sites option.

At this point, I believe you have a deeper understanding of "how to plug memory leaks with weak references in Java". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report