Я создал простой портлет vaadin в контексте Liferay 7 / DXP или osgi 6, и я заметил, что мои ссылки не собирают мусор, если я использую декларативные службы osgi с областью прототипа, но они делают, если я использую serviceObjects,Почему?
Примечание. Я обновил этот вопрос и поставил в конце еще более простой пример.
Мой основной компонент - это компонент-прототип, имеющий ссылку на прототип объекта.Если я использую декларативные службы osgi для объявления своей зависимости (HelloPresenter в следующем листинге), моя зависимость не будет освобождена и останется в куче навсегда:
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceScope;
import org.osgi.service.component.annotations.ServiceScope;
/**
* Created by marcel
*/
@Component(
property = {
"com.liferay.portlet.display-category=VaadinHelloMvp",
"javax.portlet.display-name=VaadinHelloMvp",
"javax.portlet.name=VaadinHelloMvp",
"com.vaadin.osgi.liferay.portlet-ui=true"
},
service = UI.class,
scope = ServiceScope.PROTOTYPE
)
public class VaadinHelloMvpPortlet extends UI {
@Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
private HelloPresenter helloPresenter;
@Override
protected void init(VaadinRequest request) {
this.setContent(helloPresenter.getViewComponent());
}
}
Итак, я попытался получитьмой экземпляр службы для моего HelloPresenter программным способом, который прекрасно работает:
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceObjects;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ServiceScope;
/**
* Created by marcel
*/
@Component(
property = {
"com.liferay.portlet.display-category=VaadinHelloMvp",
"javax.portlet.display-name=VaadinHelloMvp",
"javax.portlet.name=VaadinHelloMvp",
"com.vaadin.osgi.liferay.portlet-ui=true"
},
service = UI.class,
scope = ServiceScope.PROTOTYPE
)
public class VaadinHelloMvpPortlet extends UI {
private HelloPresenter helloPresenter;
@Override
protected void init(VaadinRequest request) {
Bundle bundle = FrameworkUtil.getBundle(HelloPresenter.class);
ServiceReference<HelloPresenter> serviceReference = bundle.getBundleContext().getServiceReference(HelloPresenter.class);
ServiceObjects<HelloPresenter> serviceObjects = bundle.getBundleContext().getServiceObjects(serviceReference);
helloPresenter = serviceObjects.getService();
this.addDetachListener(event -> serviceObjects.ungetService(helloPresenter));
helloPresenter.init();
this.setContent(helloPresenter.getViewComponent());
}
}
Так что мне интересно, почему мой HelloPresenter не будет выпущен средой osgi в первом сценарии, а во втором?1011 *
Мой объект портлета (UI) также создается с помощью
serviceObjects.getService();
и освобождается с помощью
serviceObjects.ungetService(uiObject);
, и я пробовал другие сценарии, в которых я устанавливал другую ссылку на прототип в своем HelloPresenter, который также создаст ссылку, которая не будет выпущена и сборка мусора.Так что мой опыт заключался в том, что всякий раз, когда вы создаете объект службы, который содержит ссылку на прототип, ссылка не будет освобождена и застревает в куче jvm после освобождения объекта службы
. Поэтому у меня возникла идея, что либоЯ делаю что-то не так или пропускаю параметр, из-за которого моя ссылка на прототип никогда не выпускается ИЛИ что-то не так с смешиванием декларативного сервиса osgi и объектов serviceObjects ...
Знаете ли вы, как я могу заставить работать мой первый пример?Я хочу использовать аннотации, а также быть уверенным, что они закрываются после закрытия моего интерфейса портлета.
ОБНОВЛЕНИЕ
Я создал еще один пример скомпонент singleton для выполнения команды оболочки gogo и объекта-прототипа, который также содержит ссылку на прототип:
@Component(
service = GogoShellService.class,
scope = ServiceScope.SINGLETON,
immediate = true,
property =
{
"osgi.command.scope=test",
"osgi.command.function=atest",
}
)
public class GogoShellService {
public String atest() {
Bundle bundle = FrameworkUtil.getBundle(APrototypeComponent.class);
ServiceReference<APrototypeComponent> serviceReference = bundle.getBundleContext().getServiceReference(APrototypeComponent.class);
ServiceObjects<APrototypeComponent> serviceObjects = bundle.getBundleContext().getServiceObjects(serviceReference);
APrototypeComponent service = serviceObjects.getService();
String s = "Hello From: " + service.sayHello();
serviceObjects.ungetService(service);
return s;
}
}
@Component(scope = ServiceScope.PROTOTYPE, service = APrototypeComponent.class, servicefactory = true)
public class APrototypeComponent {
@Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
AProInAProComp aProInAProComp;
public String sayHello() {
String hello = "Hello From " + this.getClass().getSimpleName() + "(" + this.toString() + ") ";
if (aProInAProComp != null) {
hello += aProInAProComp.sayHello();
}
return hello;
}
}
@Component(scope = ServiceScope.PROTOTYPE, service = AProInAProComp.class)
public class AProInAProComp {
public String sayHello() {
return "Hello From " + this.getClass().getSimpleName() + "(" + this.toString() + ")";
}
}
Каждый раз, когда я выполняю команду (GogoShellService # atest), создается новый экземпляр прототипа, который также должен быть уничтоженвпоследствии, но я все еще вижу этот объект в своей куче, и запуск сборки мусора не очищает это ...
Вывод отладки osgi следующий:
[org_apache_felix_scr:94] getService {de.foo.bar.bax.gogo.GogoShellService}={osgi.command.function=atest, component.name=de.foo.bar.bax.gogo.GogoShellService, component.id=2944, osgi.command.scope=test, service.id=7827, service.bundleid=51, service.scope=bundle}: stack of references: []
APrototypeComponent(2942)] ServiceFactory.getService()
AProInAProComp(2941)] ServiceFactory.getService()
AProInAProComp(2941)] This thread collected dependencies
AProInAProComp(2941)] getService (ServiceFactory) dependencies collected.
AProInAProComp(2941)] Querying state active
AProInAProComp(2941)] Changed state from active to active
APrototypeComponent(2942)] This thread collected dependencies
APrototypeComponent(2942)] getService (ServiceFactory) dependencies collected.
APrototypeComponent(2942)] Querying state satisfied
APrototypeComponent(2942)] For dependency aProInAProComp, optional: false; to bind: [[MultiplePrototypeRefPair: ref: [{de.foo.bar.bax.checkosgi.AProInAProComp}={component.name=de.foo.bar.bax.checkosgi.AProInAProComp, component.id=2941, service.id=7823, service.bundleid=51, service.scope=prototype}] has service: [true]]]
APrototypeComponent(2942)] Changed state from satisfied to active
APrototypeComponent(2942)] ServiceFactory.ungetService()
APrototypeComponent(2942)] DependencyManager: aProInAProComp close component unbinding from org.apache.felix.scr.impl.manager.ComponentContextImpl@3927bc1d at tracking count 1 refpairs: [[MultiplePrototypeRefPair: ref: [{de.foo.bar.bax.checkosgi.AProInAProComp}={component.name=de.foo.bar.bax.checkosgi.AProInAProComp, component.id=2941, service.id=7823, service.bundleid=51, service.scope=prototype}] has service: [true]]]
APrototypeComponent(2942)] Querying state active
APrototypeComponent(2942)] Changed state from active to satisfied
Надеюсьне понимаю, почему мои прототипы не могут собирать мусор ...