[JBoss AOP] - Re: probleam in granularity of interception
by fabiocsilva
Weaving mode: compile-time
jboss-aop.xml:
|
|
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
| <aop>
|
| <aspect class="aspects.distribution.HealthWatcherServerSideAspect"
| scope="PER_VM" />
|
| <aspect class="aspects.distribution.HealthWatcherClientSideAspect"
| scope="PER_VM" />
|
|
|
| <aspect class="aspects.dataManagement.nonpersistent.DataCollectionNonPersistent"
| scope="PER_VM" />
|
|
| <!--
| <aspect class="aspects.dataManagement.persistent.DataCollectionPersistent"
| scope="PER_VM" />
| -->
|
|
| <aspect class="aspects.dataManagement.persistent.PersistenceControlHealthWatcher"
| scope="PER_VM" />
|
|
| <introduction
| expr="class(complaint.ComplaintRecord)
| OR class(healthGuide.HealthUnitRecord)
| OR class(healthGuide.MedicalSpecialtyRecord)
| OR class(employee.EmployeeRecord)
| OR class(complaint.DiseaseRecord)">
| <mixin>
| <interfaces>
| aspects.dataManagement.util.SystemRecord
| </interfaces>
| <class>aspects.dataManagement.util.SystemRecordImpl</class>
| <construction>
| new aspects.dataManagement.util.SystemRecordImpl()
| </construction>
| </mixin>
| </introduction>
|
|
| <pointcut
| expr="execution(public void gui.servlets.ServletWebServer->init(javax.servlet.ServletConfig))"
| name="facadeMainExecution" />
|
| <bind pointcut="facadeMainExecution">
| <advice
| aspect="aspects.distribution.HealthWatcherServerSideAspect"
| name="beforeFacadeMainExecution" />
| </bind>
|
|
| <pointcut name="facadeCallers"
| expr="within($instanceof{javax.servlet.http.HttpServlet})" />
|
|
| <pointcut name="facadeCalls"
| expr="call(* controllers.HealthWatcherFacade->*(..)) AND !call(static * controllers.HealthWatcherFacade->*(..))" />
|
|
|
| <bind pointcut="facadeCallers AND facadeCalls">
| <advice
| aspect="aspects.distribution.HealthWatcherClientSideAspect"
| name="aroundFacadeLocalCalls" />
| </bind>
|
| <!--
| <pointcut name="recordsCreation"
| expr="all($instanceof{aspects.dataManagement.util.SystemRecord}) AND !within($instanceof{aspects.dataManagement.AbstractDataCollectionCustomization})" />
| -->
|
| <pointcut name="recordsCreation"
| expr="call(employee.EmployeeRecord->new(..))" />
|
| <bind pointcut="recordsCreation">
| <advice
| aspect="aspects.dataManagement.nonpersistent.DataCollectionNonPersistent"
| name="aroundRecordsCreation" />
| <!--
| <advice
| aspect="aspects.dataManagement.persistent.DataCollectionPersistent"
| name="aroundRecordsCreation" />
| -->
| </bind>
|
|
|
| <pointcut name="connectionOperations" expr="call(void IPersistenceMechanism->connect()) OR
| call(void IPersistenceMechanism->disconnect())" />
|
|
|
|
|
|
| <pointcut name="obtainPmInstance"
| expr="call(* aspects.dataManagement.dataCollections.rdbms.PersistenceMechanismRDBMS->getInstance(..))" />
|
|
|
| <pointcut name="initSystem"
| expr="call(controllers.HealthWatcherFacade->new())" />
|
| <bind pointcut="initSystem">
| <advice
| aspect="aspects.dataManagement.persistent.PersistenceControlHealthWatcher"
| name="adviceInitSystem" />
| </bind>
|
|
|
| </aop>
|
|
|
ServletInit.java
|
|
| package gui.servlets;
|
|
|
| import java.io.IOException;
|
|
|
| import javax.servlet.ServletConfig;
|
| import javax.servlet.ServletException;
|
| import javax.servlet.http.HttpServlet;
|
| import javax.servlet.http.HttpServletRequest;
|
| import javax.servlet.http.HttpServletResponse;
|
|
|
| import controllers.HealthWatcherFacade;
|
| import employee.EmployeeRecord;
|
|
| public class ServletInit extends HttpServlet {
|
|
|
|
|
|
|
|
|
|
|
| public void init(ServletConfig config) throws ServletException {
|
| HealthWatcherFacade.getInstance();
|
|
|
| }
|
|
|
| public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
| HealthWatcherFacade.getInstance();
|
|
|
| }
|
|
|
| public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
| HealthWatcherFacade.getInstance();
|
| }
|
| }
|
|
HealthWatcherFacade.java
|
|
| package controllers;
|
|
|
| import complaint.*;
|
| import employee.Employee;
|
| import employee.EmployeeRecord;
|
| import exceptions.ObjectAlreadyInsertedException;
|
| import exceptions.ObjectNotFoundException;
|
| import exceptions.ObjectNotValidException;
|
| import healthGuide.HealthUnit;
|
| import healthGuide.HealthUnitRecord;
|
| import healthGuide.MedicalSpecialtyRecord;
|
| import util.IteratorHW;
|
|
|
|
|
| public class HealthWatcherFacade {
|
|
|
| private static HealthWatcherFacade singleton;
|
| private ComplaintRecord complaintRecord;
|
| private HealthUnitRecord healthUnitRecord;
|
| private MedicalSpecialtyRecord specialtyRecord;
|
| private DiseaseRecord diseaseRecord;
|
| private EmployeeRecord employeeRecord;
|
|
|
| private HealthWatcherFacade() {
|
| complaintRecord = new ComplaintRecord(null);
|
| healthUnitRecord = new HealthUnitRecord(null);
|
| specialtyRecord = new MedicalSpecialtyRecord(null);
|
| diseaseRecord = new DiseaseRecord(null);
|
| employeeRecord = new EmployeeRecord(null);
|
| }
|
| public synchronized static HealthWatcherFacade getInstance() {
|
| if (singleton == null) {
|
| singleton = new HealthWatcherFacade();
|
| }
|
|
|
| return singleton;
|
| }
|
|
|
| public Employee searchEmployee(String login) throws ObjectNotFoundException {
|
| return employeeRecord.search(login);
|
| }
|
| public void update(Employee employee) throws ObjectNotFoundException, ObjectNotValidException {
|
| employeeRecord.update(employee);
|
| }
|
| public void insert(Employee employee) throws ObjectAlreadyInsertedException, ObjectNotValidException {
|
| employeeRecord.insert(employee);
|
| }
|
|
|
| public int insert(Complaint complaint) throws ObjectAlreadyInsertedException, ObjectNotValidException {
|
| return complaintRecord.insert(complaint);
|
| }
|
| public void update(Complaint complaint) throws ObjectNotFoundException, ObjectNotValidException {
|
| complaintRecord.update(complaint);
|
| }
|
| public Complaint searchComplaint(int complaintCode) throws ObjectNotFoundException {
|
| return complaintRecord.search(complaintCode);
|
| }
|
| public void update(HealthUnit unit) throws ObjectNotFoundException, ObjectNotValidException {
|
| healthUnitRecord.update(unit);
|
| }
|
| public HealthUnit searchHealthUnit(int healthUnitCode) throws ObjectNotFoundException {
|
| return healthUnitRecord.search(healthUnitCode);
|
| }
|
| public IteratorHW searchHealthUnitsBySpecialty(int specialtyCode) throws ObjectNotFoundException {
|
| return healthUnitRecord.searchHealthUnitsBySpecialty(specialtyCode);
|
| }
|
| public IteratorHW getHealthUnitList() throws ObjectNotFoundException {
|
| return healthUnitRecord.getHealthUnitList();
|
| }
|
| public IteratorHW searchSpecialtiesByHealthUnit(int healthUnitCode) throws ObjectNotFoundException {
|
| return healthUnitRecord.searchSpecialtiesByHealthUnit(healthUnitCode);
|
| }
|
| public IteratorHW getComplaintList() throws ObjectNotFoundException {
|
| return complaintRecord.getComplaintList();
|
| }
|
| public IteratorHW getSpecialtyList() throws ObjectNotFoundException {
|
| return specialtyRecord.getSpecialtyList();
|
| }
|
| public DiseaseType searchDiseaseType(int diseaseCode) throws ObjectNotFoundException {
|
| return diseaseRecord.search(diseaseCode);
|
| }
|
| public IteratorHW getDiseaseTypeList() throws ObjectNotFoundException {
|
| return diseaseRecord.getDiseaseTypeList();
|
| }
|
| }
|
|
|
EmployeeRecord.java
|
|
| package employee;
|
|
|
| import exceptions.ExceptionMessages;
|
| import exceptions.ObjectAlreadyInsertedException;
|
| import exceptions.ObjectNotFoundException;
|
| import exceptions.ObjectNotValidException;
|
| public class EmployeeRecord implements util.RecordTag{
|
|
|
| private IEmployeeRepository employeeRepository;
|
|
|
| public EmployeeRecord(IEmployeeRepository rep) {
|
| this.employeeRepository = rep;
|
| }
|
|
|
| public Employee search(String login) throws ObjectNotFoundException {
|
| return employeeRepository.search(login);
|
| }
|
|
|
| public void insert(Employee employee) throws ObjectAlreadyInsertedException, ObjectNotValidException {
|
| if (employeeRepository.exists(employee.getLogin())) {
|
| throw new ObjectAlreadyInsertedException(ExceptionMessages.EXC_JA_EXISTE);
|
| } else {
|
| employeeRepository.insert(employee);
|
| }
|
| }
|
|
|
| public void update(Employee employee) throws ObjectNotFoundException, ObjectNotValidException {
|
| employeeRepository.update(employee);
|
| }
|
| }
|
message when new EmployeeRecord(null) is called inside servlet:
| 23:12:45,341 INFO [STDOUT] aroundRecordsCreation:class gui.servlets.ServletInit_1_ConByMInvocation
| 23:12:45,369 INFO [STDOUT] aroundRecordsCreation:class gui.servlets.ServletInit_3_ConByMInvocation
|
When the method HealthWatcherFacade.getInstance() is called the attribute modified in the constructor of EmployeeRecord is intercepted(I used keyword ?all? to discover this interception):
private IEmployeeRepository employeeRepository;
public EmployeeRecord(IEmployeeRepository rep) {
this.employeeRepository = rep;
}
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3992143#3992143
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3992143
19 years, 4 months
[Messaging, JMS & JBossMQ] - Memory leak caused by Connection$PingTask
by johnamos
JBoss [Zion] 4.0.3SP1 (build: CVSTag=JBoss_4_0_3_SP1 date=200510231054)
ClockDaemon is used by org.jboss.mg.Connection to periodically run Connection$PingTask. ClockDaemon holds a Heap that contains references to PingTask instances. Normally, the PingTask instances are removed from the ClockDaemon's Heap by ClockDaemon$RunLoop, which contains an infinite loop that runs each PingTask.
Ocassionally, after running my web application for 20-30 hours, I start to see a memory leak that is caused by references to objects in the ClockDaemon's Heap.
My application has a scheduler that issues a JMS event every 30 seconds, and each one instantiates a new Connection. The constructor for Connection calls startPingThread(), which runs
| clockDaemon.executePeriodically(pingPeriod, new PingTask(), true);
This method call inserts a new ClockDaemon$TaskNode on the ClockDaemon's Heap.
When I put my debugger on the leaking application, I see that ClockDaemon$RunLoop is hung on the following line:
task.command.run();
The task is a TaskNode instance with a command that is a PingTask instance. As a result, the loop is stopped, so none of the objects can be removed from the ClockDaemon's Heap.
Drilling down into the PingTask.run() method, I see that it is hung at the following line:
pingTaskSemaphore.acquire();
My debugger shows that pingTaskSemaphore has zero permits, so the acquire() method will block until another thread calls pingTaskSemaphore.release(). But apparently release() is never called.
It seems to me that this should never be allowed to happen, because a low priority ping task is effectively hijacking the ClockDaemon's loop that dereferences objects. Once the application reaches this state, the JVM ultimately fails with an OutOfMemory error.
I don't immediately see why pingTaskSemaphore.release() is never called, except that pingTaskSemaphore.acquire() is not in the same try-finally block. The PingTask.run() method is below:
| /**
| * The ping task
| */
| class PingTask implements Runnable
| {
| /**
| * Main processing method for the PingTask object
| */
| public void run()
| {
| try
| {
| pingTaskSemaphore.acquire();
| }
| catch (InterruptedException e)
| {
| log.debug("Interrupted requesting ping semaphore");
| return;
| }
| try
| {
| if (ponged == false)
| {
| // Server did not pong use with in the timeout
| // period.. Assuming the connection is dead.
| throw new SpyJMSException("No pong received", new IOException("ping timeout."));
| }
|
| ponged = false;
| pingServer(System.currentTimeMillis());
| }
| catch (Throwable t)
| {
| asynchFailure("Unexpected ping failure", t);
| }
| finally
| {
| pingTaskSemaphore.release();
| }
| }
| }
|
Notice that pingTaskSemaphore.release() is in a finally block, but it isn't the same try block as the pingTaskSemaphore.acquire() method call, which means that it is possible for pingTaskSemaphore.acquire() to decrement the Semaphore's permits and then throw an exception that is not InterruptedException. In that case, the finally block would never be executed because the Exception would be thrown from the first try block. However, this last paragraph is speculation. I don't really know what is happening. I also don't know why it takes 20-30 hours of operation for this problem to appear. I don't have a reproducible test case because I can't consistently reproduce this problem.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3992141#3992141
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3992141
19 years, 4 months