Library is alredy loaded in another classloader

  • Автор темы lionk
  • Дата начала
L

lionk

Есть Ява-библиотека, которая работает с функциями спрятанными в ДЛЛ.
Java:
class JavaDLL {  
    public native int Execute();    //функция в ДЛЛ
   
    static {
        System.loadLibrary("mydll");    // подключил ДЛЛ
    }
   
}

public class HASP {
    private JavaDLL oHASP;
   
    public int iniHASP() {
        oHASP = new JavaDLL();    //создал объект
        int ret = oHASP.Execute();    //выполнил
        oHASP = null;    //обнулил чтобы GC освободил ресурс !!!
        System.gc();    // напомнил
        return ret;
    }
   
}

Делаю её отображение в LS-библиотеке, для удобства, вот функция которую вызываю:
Visual Basic:
' 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
7 985
611
BIT
471
причина, КМК, кроется именно в класслоадере, при экшенах - происходит "очистка" классов, а в агенте - нет

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

lionk

причина, КМК, кроется именно в класслоадере, при экшенах - происходит "очистка" классов, а в агенте - нет

Добавлено:

И изменить положение дел невозможно?

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

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 985
611
BIT
471
помимо статика там есть вызо нэйтив АПИ, кот подразумевает синглтон, кот. отстутствует :)
И изменить положение дел невозможно?
и почему же не вынести в jar файл свой код и сложить его в jvm/lib/ext/ ?

Добавлено:
Java:
oHASP = null;    //обнулил чтобы GC освободил ресурс !!!   
System.gc();    // напомнил   
return ret;
ничего не освободится, вызов gc не гарантирует освобожение IO, нативных ресурсов... и ваще не слушает ваших похотелок (вызов - не иструкция для исполнения, а лишь констатация намерения ;)
 
L

lionk

и почему же не вынести в jar файл свой код и сложить его в jvm/lib/ext/ ?

Не понял, в jar-файлик - вывести ява либу из лотуса?
И в лотус-либе обращаться к этому выносному файлику?
Разве есть принципиальная разница между библиотекой в базе и внешней?
 
T

turumbay

Разве есть принципиальная разница между библиотекой в базе и внешней?
Код на кнопке грузится класслоадером lotus.domino.JavaConnectLoader - так называемый бридж. Соответственно и либа грузится им же.
В клиенте (точнее в notes jvm) ровно один экземпляр такого класслоадера, поэтому повторные попытки грузить либу тихо игнорируются.

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

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

Обучение наступательной кибербезопасности в игровой форме. Начать игру!