Italian B4J - Error Java OutOfMemoryError

Discussion in 'Italian Forum' started by marco.canta, May 11, 2018.

  1. marco.canta

    marco.canta Active Member Licensed User

    Buongiorno, ho realizzato diversi programmi con il B4j e sempre con molta semplicità e soddisfazione, questa volta ho realizzato un software che deve girare senza essere mai chiuso 24h su 24, e che legge, scrive e aggiorna un database mySQL (MAMP).
    Il programma sembra funzionare ed eseguire tutte le sue procedure, unico problema (e non da poco), ogni tanto si blocca e arriva questo errore :

    Java.lang.OutOfMemoryError: Java heap Space

    Non so cosa lo possa generare e quindi dove andare a risolvere, mi occorre un vostro aiuto.

    Grazie Marco.



    [​IMG]
     
  2. udg

    udg Expert Licensed User

    Una prima misura è aumentare lo spazio heap a disposizione della JVM.
    Ma è probabile che ci sia qualcosa nel programma che richiede risorse che poi non libera e quindi il garbage collector (quando, con comodo, decide di partire) non libera tutto ciò che potrebbe e passo dopo passo il tuo heap si satura.

    Qui trovi un paio di spunti.
     
    marco.canta likes this.
  3. LucaMs

    LucaMs Expert Licensed User

    marco.canta likes this.
  4. Star-Dust

    Star-Dust Expert Licensed User

    Fallo girare in debug e vedi se identifichi la riga che genera l'errore
     
  5. marco.canta

    marco.canta Active Member Licensed User

    Ho fatto girare in Debug, ma non sono usciti errori. Credo che sia un problema legato alla memoria e alla gestione del mySQL.
    Io faccio molti accessi al mySQL e forse è proprio quello che blocca .


    ad inizio programma creo la connessione .... che poi chiudo solamente a chiusura programma.

    Code:
    Sub DB64_Connect()
        
    Try
            Main.mySQL.Initialize2(
    "com.mysql.jdbc.Driver""jdbc:mysql://" & Main.ValIP_mySQL & ":" & Main.ValPort_mySQL & "/mySQL?characterEncoding=utf8",               Main.ValUser_mySQL, Main.ValPass_mySQL)
            
    Log("- mySQL Connected")
        
    Catch
            
    Log("*! mySQL  ** Error **")
        
    End Try
    End Sub


    e ogni 250 millisecondi (tramite TIMER) faccio la lettura o scrittura alle tabelle con un codice come il seguente :

    Code:
    Sub mySQL_Read()
        
    Dim rs As ResultSet = Main.mySQL.ExecQuery("SELECT * FROM Impianto")
        rs.NextRow
            Main.ValCodImpianto = rs.GetString(
    "CodImpianto")
            Main.ValDescImpianto = rs.GetString(
    "DescImpianto")
        rs.Close
    End Sub
    qualche aiuto o suggerimento ?

    Grazie Marco.
     
  6. udg

    udg Expert Licensed User

    Erel suggersice l'utilizzo del ConnectionPool. Qualcosa tipo:

    Code:
    Sub Process_Globals
       
    Private pool As ConnectionPool
    End Sub

    Public Sub InitDB
       pool.Initialize(
    "com.mysql.jdbc.Driver""jdbc:mysql://localhost:3306/?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull",...)
    End Sub

    Public Sub getData
      ...
       
    Dim sql1 As SQL = pool.GetConnection
       sql1.BeginTransaction
       
    Try
           
    Dim Cursor As ResultSet
           
    Cursor = sql1.ExecQuery($"SELECT * FROM ...;"$)
           
    Do While Cursor.NextRow
               .....
           
    Loop
            ..
           sql1.TransactionSuccessful
       
    Catch
           ...
           sql1.Rollback
       
    End Try
       
    Cursor.Close
       sql1.Close
    End Sub
    In pratica quando devi accedere ai dati ti fai dare un nuovo oggetto dal pool e quando hai finito lo chiudi (così come per il RS). Ci pensa il pool a rilasciare la connessione.
     
    Last edited: May 12, 2018
    LucaMs and marco.canta like this.
  7. marco.canta

    marco.canta Active Member Licensed User

    Grazie 'udg' ... oggi provo, speriamo funzioni !
     
  8. udg

    udg Expert Licensed User

    Di nulla. Valuta anche se nel tuo caso le transazioni siano necessarie.
    Mi sembra che tu legga un unico record; in tal caso completa lo statemenet con "LIMIT 1" in modo che il cursor non debba recuperarli tutti per poi utilizzarne uno solo. Presumendo che tu desideri quello più recente sarebbe bene introdurre un "WHERE" su un campo data o data/ora o al peggio sull'id dove selezioni il maggiore.
     
    Last edited: May 12, 2018
    LucaMs likes this.
  9. marco.canta

    marco.canta Active Member Licensed User

    Grazie del suggerimento, si in effetti uso spesso la lettura di un solo record e lo filtro con un WHERE ...


    Fatte prime prove e primi errori ...

    per la connessione utilizzo questo connector ... "#AdditionalJar: mysql-connector-java-5.1.27-bin.jar"
    e connetto il DB mySQL che gira su MAMP con il seguente codice :

    Code:
    Try
            
    Log("try ... InitDB")
            ConPool.Initialize(
    "com.mysql.jdbc.Driver""jdbc:mysql://localhost:8889/DB64?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull""root""root")
        
    Catch
            
    Log("Last Pool Init Except: "&LastException.Message)
        
    End Try
    e questo è l errore a cui non riesco a venirne a capo ...
    [​IMG]

    e ora dove metto le mani ? ehehehe ....
     
  10. LucaMs

    LucaMs Expert Licensed User

    In effetti, non leggo un errore specifico.
    Sto per DANDO un'occhiata a come accedo al mio e ti faccio sapere.
    Tu, intanto... canta :p
     
  11. LucaMs

    LucaMs Expert Licensed User

    Donq... siccome non me va de pensa' troppo ma di dare una zampa sì, pubblico direttamente il codice.

    E' in un modulo, una routine pubblica Init:
    Code:
    Dim JdbcUrl As String = Main.settings.Get("JdbcUrl")
    Dim driverClass As String = Main.settings.Get("DriverClass")
    Dim dbuser As String = Main.settings.Get("DBUser")
    Dim dbpassword As String = Main.settings.Get("DBPassword")

    pool.Initialize(driverClass, JdbcUrl, dbuser, dbpassword)
    Vado a vedere il resto (cosa diavolo ci sia in quella che suppongo sia una map, settings ed aggiungo a questo stesso post)...


    Infatti è una map (nel Main, come si vede nel codice sopra):
    settings = File.ReadMap(File.DirApp, "settings.txt")


    #AdditionalJar: C:\Program Files (x86)\MySQL\MySQL Connector J\mysql-connector-java-5.1.32-bin.jar


    file settings.txt:

    JdbcUrl=jdbc:mysql://localhost/MyGame1?characterEncoding=utf8
    DriverClass=com.mysql.jdbc.Driver
    DBUser=[omissis]
    DBPassword=[omissis]
    DBMyGameAdmin=[omissis]
    DBMyGameAdminPassword=[omissis]
     
    marco.canta likes this.
  12. udg

    udg Expert Licensed User

    Quello del post #9 non è un errore. Sono le prime righe dell'attivazione.
    Poi dovresti avere qualcosa tipo :
    "2018-05-12 10:20:57.170:INFO::main: Logging initialized @855ms to org.eclipse.jetty.util.log.StdErrLog"
    ed altre, fino a:
    "2018-05-12 10:20:57.493:INFO:eek:ejs.Server:main: Started @1178ms"

    A meno che per "errore" non intendi che tutto si pianta dopo quelle 4 righe..
     
    marco.canta likes this.
  13. LucaMs

    LucaMs Expert Licensed User

    Oh, poi, per quanto riguarda le query... una routine che uso (non adatta per tutto, non in scrittura, ad esempio):
    Code:
    Private Sub ExecNonQuery2(Query As String, Args As ListAs Boolean
        
    Dim Result As Boolean = True
       
        
    Dim sq As SQL = pool.GetConnection
        
    Try
            sq.ExecNonQuery2(mQuery, Args)
        
    Catch
            
    Log(LastException)
            Result = 
    False
        
    End Try
        sq.Close  
       
        
    Return Result
    End Sub
     
    marco.canta likes this.
  14. marco.canta

    marco.canta Active Member Licensed User

    LucasMs ... rileggendo il tuo post precedente dove dicevi che non vedevi errori ... continuato a scrivere codice e leggere i record ....

    Funziona !!! leggo correttamente i record ... ora cerco di ottimizzare il codice.

    tra le cose che avevo letto sul forum avevo trovato anche questa parte di codice da inserire dopo la connessione

    Code:
    Dim jo As JavaObject = ConPool
        jo.RunMethod(
    "setMaxPoolSize"Array(100))
    potrebbe avere senso ?
     
  15. LucaMs

    LucaMs Expert Licensed User

    Dipende da quale sia il valore di default; se fosse infinito o 1.000, ad esempio, impostandolo potresti solo avere ulteriori crash, non certo miglioramenti.
     
  16. udg

    udg Expert Licensed User

    Considerando che prevedi di aprirne 4 al secondo, presumo che un limite ridotto possa facilmente condurre ad errori di mancata allocazione. Un limite alto invece dovrebbe condurre a maggior occupazione di memoria. Puoi cercare un equilibrio tra i due fattori ed utilizzare quel codice per "restare al comando"; in caso di problemi sapresti dover metter mani.
     
    marco.canta likes this.
  17. LucaMs

    LucaMs Expert Licensed User

    Se non sbaglio, di default il massimo è 15, quindi è probabile che impostarlo su 100 migliori le prestazioni.
     
    marco.canta likes this.
  18. marco.canta

    marco.canta Active Member Licensed User

    Ho fatto un programma per Test ... ora lo lascio girare per qualche ora e vi aggiorno.

    per ora Grazie del supporto :)
     
  19. marco.canta

    marco.canta Active Member Licensed User

    Al momento ancora sembra funziona senza bloccarsi .

    Ma se volessi utilizzare due database mySQL1 e mySQL2 posso utilizzare una sola ConnectionPool o ne devo istanziare due distinte ?
     
  20. LucaMs

    LucaMs Expert Licensed User

    "♪♫... e come stai? Domanda inutile ♪♫"

    :)


    JdbcUrl, usato per inizializzare la connection pool, punta ad un preciso db, quindi ti serviranno due distinte connessioni (pool).
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice