Library Is Alredy Loaded In Anover Classloader

lionk

Well-known member
05.04.2007
310
2
#1
Есть Ява-библиотека, которая работает с функциями спрятанными в ДЛЛ.


C++:
class JavaDLL
{	
public native int Execute();//функция в ДЛЛ

static {
System.loadLibrary("mydll"); // подключил ДЛЛ
}

}
public class HASP 
{
private JavaDLL oHASP;

public int iniHASP(){
oHASP = new JavaDLL(); //создал объект
int ret;
ret=oHASP.Execute(); //выполнил
oHASP=null; //обнулил чтобы GC освободил ресурс !!!
System.gc(); // напомнил
return ret; 
}
}
Делаю её отображение в LS-библиотеке, для удобства, вот функция которую вызываю:


Код:
' js, jHASPClass, jHASPObject - глобальные чтобы при вызове на форме не инициализировать по несколько раз

If js Is Nothing Then
Set js = New JAVASESSION
End If
If jHASPClass Is Nothing Then
Set jHASPClass = js.GetClass("HASP")
End If
If jHASPObject Is Nothing Then
Set jHASPObject = jHASPClass.CreateObject
End If

call jHASPObject.iniHASP()

Так вот проблема:

Если я выполняю ls-функцию в "Действии" или событии формы всё работает, можно даже по несколько раз подряд запускать.

Если ls-функцию положить в "Агента" - то получаю ошибку "library is alredy loaded in anover ClassLoader", если эту ls-функцию уже хоть раз вызывали (например в действии или событии формы).
Если к ls-функции не было обращений, и вызвать её через агента, то она один раз отработает, и но при следующем запуске выдаст ошибку "о занятой библиотеке". НО из "действяи" будет продолжать работать.

В чём дело?
 

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 601
277
#2
причина, КМК, кроется именно в класслоадере, при экшенах - происходит "очистка" классов, а в агенте - нет

Добавлено:
Изменяемые статичные объекты
Также частым случаям утечки памяти в Java-приложениях служит неправильное использование static. Статичная переменная хранится своим классом, а как следствие, его загрузчиком (classloader). По причине внешнего использования увеличивается шанс, что сборщик мусора не соберёт данный экземпляр. Также зачастую в static-переменных кэшируется информация или же хранятся состояния, используемые несколькими потоками. Отдельным примером являются статичные коллекции. Хорошим же тоном при архитектурном проектировании служит полное избегание изменяемых статичных объектов — зачастую существует лучшая альтернатива.
http://habrahabr.ru/blogs/java/132500/
 

lionk

Well-known member
05.04.2007
310
2
#3
причина, КМК, кроется именно в класслоадере, при экшенах - происходит "очистка" классов, а в агенте - нет

Добавлено: http://habrahabr.ru/blogs/java/132500/
И изменить положение дел невозможно?

Переписал класс без параметра static, подключаю библиотек в конструкторе, ситуация не изменилась.
По ссылке указано что есть замена, но погуглив ничего подходящего не нашёл.
 

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 601
277
#4
помимо статика там есть вызо нэйтив АПИ, кот подразумевает синглтон, кот. отстутствует :)
И изменить положение дел невозможно?
и почему же не вынести в jar файл свой код и сложить его в jvm/lib/ext/ ?

Добавлено: <!--shcode--><pre><code class='java'>oHASP=null; //обнулил чтобы GC освободил ресурс !!!
System.gc(); // напомнил
return ret;[/CODE]ничего не освободится, вызов gc не гарантирует освобожение IO, нативных ресурсов... и ваще не слушает ваших похотелок (вызов - не иструкция для исполнения, а лишь констатация намерения ;) )
 

lionk

Well-known member
05.04.2007
310
2
#5
и почему же не вынести в jar файл свой код и сложить его в jvm/lib/ext/ ?
Не понял, в jar-файлик - вывести ява либу из лотуса?
И в лотус-либе обращаться к этому выносному файлику?
Разве есть принципиальная разница между библиотекой в базе и внешней?
 
13.03.2009
625
1
#7
Разве есть принципиальная разница между библиотекой в базе и внешней?
Код на кнопке грузится класслоадером lotus.domino.JavaConnectLoader - так называемый бридж. Соответственно и либа грузится им же.
В клиенте(точнее в notes jvm) ровно один экземпляр такого класслоадера, поэтому повторные попытки грузить либу тихо игнорируются.

В случае с агентом ситуация иная: код грузится экземпляром lotus.domino.AgentLoader. Причем при каждом запуске агента создается экземпляр указанного класслоадера - т.е. их может быть несколько.
Т.о. два запуска агента подряд приведут к тому, что второй раз либа будет грузится вторым класслоадером, о чем вы и получаете сообщение. До тех пор пока сборщик не собирет первый класслоадер - вы не сможете загрузить либу. Когда именно происходит сборка AgentLoader - я, честно говоря, не знаю. По идее - он должен собраться сразу, но, как минимум, возможны утечки внутри агента, которые будут препятствовать gc.

Простейший вариант решения этого квеста описал lmike: выложите класс, грузящий dll в lib/ext. В этом случае он будет грузиться class sun.misc.Launcher$ExtClassLoader, независимо от того, как вызывается код, использующий такой класс, т.к. ExtClassLoader - это системный класслоадер, который присутствует в единственном экземпляре.