BAEL-4615: Create and Detect Memory Leak in Java (#14060)

This commit is contained in:
Eugene Kovko 2023-05-20 00:00:16 +02:00 committed by GitHub
parent 2091146702
commit 7317f0816d
9 changed files with 225 additions and 0 deletions

View File

@ -5,3 +5,4 @@ This module contains articles about performance of Java applications
### Relevant Articles:
- [Possible Root Causes for High CPU Usage in Java](https://www.baeldung.com/java-high-cpu-usage-causes)
- [External Debugging With JMXTerm](https://www.baeldung.com/java-jmxterm-external-debugging)
- [Create and Detect Memory Leaks in Java](https://www.baeldung.com/java-create-detect-memory-leaks)

View File

@ -13,4 +13,11 @@
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>1.6.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,35 @@
package com.baeldung.lapsedlistener;
import static com.baeldung.lapsedlistener.UserGenerator.generateUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LapsedListenerRunner {
private static final Logger logger = LoggerFactory.getLogger(LapsedListenerRunner.class);
private static final MovieQuoteService movieQuoteService = new MovieQuoteService();
static {
movieQuoteService.start();
}
public static void main(String[] args) {
while (true) {
User user = generateUser();
logger.debug("{} logged in", user.getName());
user.subscribe(movieQuoteService);
userUsingService();
logger.debug("{} logged out", user.getName());
}
}
private static void userUsingService() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,47 @@
package com.baeldung.lapsedlistener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import net.datafaker.Faker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MovieQuoteService implements Subject {
private static final Logger logger = LoggerFactory.getLogger(MovieQuoteService.class);
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final List<Observer> observers = new ArrayList<>();
private final Faker faker = new Faker();
@Override
public void attach(Observer observer) {
logger.debug("Current number of subscribed users: {}", observers.size());
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
String quote = faker.movie().quote();
logger.debug("New quote: {}", quote);
for (Observer observer : observers) {
logger.debug("Notifying user: {}", observer);
observer.update(quote);
}
}
public void start() {
scheduler.scheduleAtFixedRate(this::notifyObservers, 0, 1, TimeUnit.SECONDS);
}
public int numberOfSubscribers() {
return observers.size();
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.lapsedlistener;
public interface Observer {
void update(String latestNews);
void subscribe(Subject subject);
void unsubscribe(Subject subject);
}

View File

@ -0,0 +1,9 @@
package com.baeldung.lapsedlistener;
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}

View File

@ -0,0 +1,70 @@
package com.baeldung.lapsedlistener;
public class User implements Observer {
private final String name;
private final String email;
private final String phone;
private final String street;
private final String city;
private final String state;
private final String zipCode;
public User(String name, String email, String phone, String street, String city, String state, String zipCode) {
this.name = name;
this.email = email;
this.phone = phone;
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getPhone() {
return phone;
}
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public String getZipCode() {
return zipCode;
}
@Override
public void update(final String quote) {
// user got updated with a new quote
}
@Override
public void subscribe(final Subject subject) {
subject.attach(this);
}
@Override
public void unsubscribe(final Subject subject) {
subject.detach(this);
}
@Override
public String toString() {
return "User [name=" + name + "]";
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.lapsedlistener;
import net.datafaker.Faker;
public class UserGenerator {
private UserGenerator() {
}
private static final Faker faker = new Faker();
public static User generateUser() {
String name = faker.name().fullName();
String email = faker.internet().emailAddress();
String phone = faker.phoneNumber().cellPhone();
String street = faker.address().streetAddress();
String city = faker.address().city();
String state = faker.address().state();
String zipCode = faker.address().zipCode();
return new User(name, email, phone, street, city, state, zipCode);
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.lapsedlistener;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class MovieQuoteServiceTest {
@Test
void whenSubscribeToService_thenServiceHasOneSubscriber() {
MovieQuoteService service = new MovieQuoteService();
service.attach(UserGenerator.generateUser());
assertEquals(1, service.numberOfSubscribers());
}
@Test
void whenUnsubscribeFromService_thenServiceHasNoSubscribers() {
MovieQuoteService service = new MovieQuoteService();
User user = UserGenerator.generateUser();
service.attach(user);
service.detach(user);
assertEquals(0, service.numberOfSubscribers());
}
}