Go has “len” as a built-in function for slices:
You can replace
if !funcoes_gerais.OutOfRange(18, Dados) {
Tensao = Dados[18]
} else {
Tensao = "0.00"
}
with
if len(Dados) > 18 {
Tensao = Dados[18]
} else {
Tensao = "0.00"
}
Go has “len” as a built-in function for slices:
You can replace
if !funcoes_gerais.OutOfRange(18, Dados) {
Tensao = Dados[18]
} else {
Tensao = "0.00"
}
with
if len(Dados) > 18 {
Tensao = Dados[18]
} else {
Tensao = "0.00"
}
I modified it but as I expected that’s still not the problem.
PS: I removed EVERYTHING from my code, every sql statement or connection, variables are now declared outside the for loop, and it still increases memory usage…
Any other thing to do?
I’m really getting frustrated about it because I’m having that problem with only 40 clients sending datagrams, whatif it was a thousand? That is the real expectation…
The same code written in Delphi, in the same server, same port, using the same database, same clients, same all… Look at the print below, that was started by now but, if you go there a week later, you’ll see the same memory and CPU usage. I liked GO lang but, how to really use it in real world if only by blowing on it, it increases memory usage?
make sure you didn’t miss any :=
declaration in the loop.
I did, I took off them all, but it still increases much memory… What I saw in some examples was that db.QueryRow() got no Close() method, like db.Query() has… 2 examples below;
Usual db.Query()
var (
id int
name string
)
rows, err := db.Query("select id, name from users where id = ?", 1)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
log.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
db.QueryRow() example
var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
Tnx.
Main code is lie that now;
package main
import "net"
import "hlsat.com.br/funcoes_gerais"
import "strings"
import "database/sql"
import "time"
import "strconv"
//import "runtime"
//import "fmt"
//import "runtime/debug"
func main() {
// carrega configuracoes iniciais e conecta no banco ---------------------------
LoadConfig()
db := ConectaBanco()
// carrega configuracoes iniciais e conecta no banco ---------------------------
// ativa o servidor udp --------------------------------------------------------
ServerAddr, udperr := net.ResolveUDPAddr("udp", ":2008")
CheckError(udperr)
ServerConn, connerr := net.ListenUDP("udp", ServerAddr)
CheckError(connerr)
defer ServerConn.Close()
buf := make([]byte, 1024)
// ativa o servidor udp --------------------------------------------------------
//AtivaLiberaMemoria()
var Dados []string
var UltimaPosicao TPonto
var PosicaoAtual TPonto
var SerieModulo string
var TipoMsg string
var Protocolo string
var EnviaACK bool
var RegistraAlerta bool
var Latitude string
var Longitude string
var StatusPosicao string
var GPSValido string
var Velocidade string
var Ignicao string
var Antifurto string
var Saida1 string
var Saida2 string
var Saida3 string
var Saida4 string
var Panico string
var Entrada1 string
var Entrada2 string
var Entrada3 string
var Entrada4 string
var Direcao string
var VelocidadeMaximaExcedida string
var BateriaCarregando string
var FalhaBateriaInterna string
var FalhaAlimentacaoPrincipal string
var Movendo string
var Tensao string
var Hodometro string
var Horimetro string
var AlertID string
var ibutton string
var DataHora time.Time
var DataHoraGPS time.Time
var IdMotorista string
var IdVeiculo string
var RegistraEventosEntradas string
var GrauAngulo int
var FiltroGPS string
var Rpm string
var SetBloqueioSireneOn string
var SetDesbloqueioSireneOff string
var SetBloqueio string
var SetDesbloqueio string
var SetSireneOn string
var SetSireneOff string
var SetReset string
var SetHorimetro string
var SetLimpaMemoria string
var GetMotoristas string
var SetComandoGenerico string
var n int
var addr *net.UDPAddr
var err error
var Rec string
var sqlcmd string
var LocalizacaoAlerta string
var stmt *sql.Stmt
var sqlres sql.Result
var rowCnt int64
for {
IdMotorista = "0"
SetBloqueioSireneOn = ""
SetDesbloqueioSireneOff = ""
SetBloqueio = ""
SetDesbloqueio = ""
SetSireneOn = ""
SetSireneOff = ""
SetReset = ""
SetHorimetro = ""
SetLimpaMemoria = ""
GetMotoristas = ""
SetComandoGenerico = ""
//RECEBE OS PACOTES NO UDP -----------------------------------------------------
n, addr, err = ServerConn.ReadFromUDP(buf)
CheckError(err)
Rec = strings.TrimSpace(string(buf[0:n]))
//RECEBE OS PACOTES NO UDP -----------------------------------------------------
Dados = strings.Split(Rec, ";")
TipoMsg = Dados[0]
if Dados[1] == "Res" {
SerieModulo = Dados[2]
} else {
SerieModulo = Dados[1]
}
Protocolo = funcoes_gerais.CopyStr(Rec, 1, 5) //SA200 ou ST300
//RESPOSTA AOS COMANDOS --------------------------------------------------------
if Dados[1] == "Res" {
GeraLog(Rec)
}
//RESPOSTA AOS COMANDOS --------------------------------------------------------
//VERIFICA SE O MÓDULO ESTÁ CADASTRADO E ATIVO NO SISTEMA-----------------------
var IdModulo string
var ACK string
err = db.QueryRow("SELECT ID, SUNTECHACK AS ACK FROM MODULOS WHERE (SERIEMODULO = ?) AND (ATIVO = 1)", SerieModulo).Scan(&IdModulo, &ACK)
if err == sql.ErrNoRows {
continue
}
EnviaACK = (ACK == "1")
//VERIFICA SE O MÓDULO ESTÁ CADASTRADO E ATIVO NO SISTEMA-----------------------
//ACK POSICAO-------------------------------------------------------------------
if EnviaACK {
enviaUDP(ServerConn, addr, Protocolo+"ACK;"+SerieModulo)
}
//ACK POSICAO-------------------------------------------------------------------
if (TipoMsg == Protocolo+"STT") || (TipoMsg == Protocolo+"ALT") { //PACOTE POSICAO ou PACOTE DE ALERTA
if Protocolo == "SA200" {
Latitude = ajustaCordenada(Dados[6])
Longitude = ajustaCordenada(Dados[7])
DataHora = time.Now()
DataHoraGPS, err = time.Parse("01/02/2006 15:04:05", extraiDataHora(Dados[3]+Dados[4]))
if err != nil {
GeraLog("Erro no tratamento de data; DataHoraGPS")
continue
}
DataHoraGPS = funcoes_gerais.DecHour(2, DataHoraGPS)
GrauAngulo = int(funcoes_gerais.Round(funcoes_gerais.StrToFloat(Dados[9])))
GPSValido = Dados[11]
VelocidadeMaximaExcedida = "0"
BateriaCarregando = "0"
FalhaBateriaInterna = "0"
FalhaAlimentacaoPrincipal = "0"
Antifurto = "0"
Movendo = "2" //2=NÃO DISPONÍVEL
Velocidade = strconv.Itoa(int(funcoes_gerais.Round(funcoes_gerais.StrToFloat(Dados[8]))))
if Dados[13] != "0.00" {
Tensao = Dados[13]
} else {
// O funcoes_gerais.OutOfRange() é porque pode ser que o rastreador esteja configurado pra não acrescentar essas informaçoes no final da string,
// se não tiver essas informações vai cair em exceção de "range out of bounds", se cair na exceção jogo 0.00
if !funcoes_gerais.OutOfRange(18, Dados) {
Tensao = Dados[18]
} else {
Tensao = "0.00"
}
}
Ignicao = funcoes_gerais.CopyStr(Dados[14], 1, 1)
Panico = "0"
Entrada1 = funcoes_gerais.CopyStr(Dados[14], 2, 1)
Entrada2 = funcoes_gerais.CopyStr(Dados[14], 3, 1)
Entrada3 = funcoes_gerais.CopyStr(Dados[14], 4, 1)
Entrada4 = "0"
Saida1 = funcoes_gerais.CopyStr(Dados[14], 5, 1)
Saida2 = funcoes_gerais.CopyStr(Dados[14], 6, 1)
Saida3 = "0"
Saida4 = "0"
Hodometro = Dados[12]
// MODELOS MAIS ANTIGOS COMO O ST210I NÃO TÊM ESSA INFORMAÇÃO OU CASO "STT_HBM" NÃO ESTEJA CONFIGURADO,
// VAI CAIR EM EXCEÇÃO, JOGAR VALORES DEFAULT NO EXCEPT.
if TipoMsg == Protocolo+"STT" {
if !funcoes_gerais.OutOfRange(19, Dados) {
Horimetro = Dados[17]
StatusPosicao = Dados[19]
} else {
Horimetro = "0"
StatusPosicao = "1"
}
if !funcoes_gerais.OutOfRange(20, Dados) {
Rpm = Dados[20]
} else {
Rpm = "0"
}
if !funcoes_gerais.OutOfRange(21, Dados) {
ibutton = Dados[21]
} else {
ibutton = ""
}
}
if TipoMsg == Protocolo+"ALT" {
AlertID = Dados[15]
if !funcoes_gerais.OutOfRange(18, Dados) {
Horimetro = Dados[16]
StatusPosicao = Dados[18]
} else {
Horimetro = "0"
StatusPosicao = "1"
}
if !funcoes_gerais.OutOfRange(19, Dados) {
Rpm = Dados[19]
} else {
Rpm = "0"
}
if !funcoes_gerais.OutOfRange(20, Dados) {
ibutton = Dados[20]
} else {
ibutton = ""
}
}
} //FIM if Protocolo == "SA200" {......................................................
if Protocolo == "ST300" {
//ST3XXModelo = Dados[2]
Latitude = ajustaCordenada(Dados[7])
Longitude = ajustaCordenada(Dados[8])
DataHora = time.Now()
DataHoraGPS, err = time.Parse("01/02/2006 15:04:05", extraiDataHora(Dados[4]+Dados[5]))
if err != nil {
GeraLog("Erro no tratamento de data; DataHoraGPS(ST300).")
continue
}
DataHoraGPS = funcoes_gerais.DecHour(2, DataHoraGPS) //AJUSTA O FUSO HORARIO.
GrauAngulo = int(funcoes_gerais.Round(funcoes_gerais.StrToFloat(Dados[10])))
GPSValido = Dados[12]
VelocidadeMaximaExcedida = "0"
BateriaCarregando = "0"
FalhaBateriaInterna = "0"
FalhaAlimentacaoPrincipal = "0"
Antifurto = "0"
Movendo = "2" //2=NÃO DISPONÍVEL
Velocidade = strconv.Itoa(int(funcoes_gerais.Round(funcoes_gerais.StrToFloat(Dados[9]))))
//Velocidade = strconv.Itoa(fmt.Printf("%03d", int(funcoes_gerais.Round(funcoes_gerais.StrToFloat(Dados[9])))))
if Dados[14] != "0.00" {
Tensao = Dados[14]
} else {
// O funcoes_gerais.OutOfRange() é porque pode ser que o rastreador esteja configurado pra não acrescentar essas informaçoes no final da string,
// se não tiver essas informações vai cair em exceção de "range out of bounds", se cair na exceção jogo 0.00
if !funcoes_gerais.OutOfRange(19, Dados) {
Tensao = Dados[19]
} else {
Tensao = "0.00"
}
}
Ignicao = funcoes_gerais.CopyStr(Dados[15], 1, 1)
Panico = "0"
Entrada1 = funcoes_gerais.CopyStr(Dados[15], 2, 1)
Entrada2 = funcoes_gerais.CopyStr(Dados[15], 3, 1)
Entrada3 = funcoes_gerais.CopyStr(Dados[15], 4, 1)
Entrada4 = "0"
Saida1 = funcoes_gerais.CopyStr(Dados[15], 5, 1)
Saida2 = funcoes_gerais.CopyStr(Dados[15], 6, 1)
Saida3 = "0"
Saida4 = "0"
Hodometro = Dados[13]
// MODELOS MAIS ANTIGOS COMO O ST210I NÃO TÊM ESSA INFORMAÇÃO OU CASO "STT_HBM" NÃO ESTEJA CONFIGURADO,
// VAI CAIR EM EXCEÇÃO, JOGAR VALORES DEFAULT NO EXCEPT.
if TipoMsg == Protocolo+"STT" {
if !funcoes_gerais.OutOfRange(20, Dados) {
Horimetro = Dados[18]
StatusPosicao = Dados[20]
} else {
Horimetro = "0"
StatusPosicao = "1"
}
if !funcoes_gerais.OutOfRange(21, Dados) {
Rpm = Dados[21]
} else {
Rpm = "0"
}
if !funcoes_gerais.OutOfRange(22, Dados) {
ibutton = Dados[22]
} else {
ibutton = ""
}
}
if TipoMsg == Protocolo+"ALT" {
AlertID = Dados[16]
if !funcoes_gerais.OutOfRange(19, Dados) {
Horimetro = Dados[17]
StatusPosicao = Dados[19]
} else {
Horimetro = "0"
StatusPosicao = "1"
}
if !funcoes_gerais.OutOfRange(20, Dados) {
Rpm = Dados[20]
} else {
Rpm = "0"
}
if !funcoes_gerais.OutOfRange(21, Dados) {
ibutton = Dados[21]
} else {
ibutton = ""
}
}
} //FIM if Protocolo == "ST300" {......................................................
//Compatibilizando no banco com o StatusPosicao do "SmartCar", mostra se a posição é atualizada ou da memória.
if StatusPosicao == "1" {
StatusPosicao = "2" //Atualizada
}
if StatusPosicao == "0" {
StatusPosicao = "3" //Memória
}
//Compatibilizando no banco com o StatusPosicao do "SmartCar", mostra se a posição é atualizada ou da memória.
if Ignicao == "1" {
Ignicao = "L"
} else {
Ignicao = "0"
}
if ((GrauAngulo >= 0) && (GrauAngulo <= 24)) || ((GrauAngulo >= 326) && (GrauAngulo <= 360)) {
Direcao = "N"
}
if (GrauAngulo >= 25) && (GrauAngulo <= 65) {
Direcao = "NE"
}
if (GrauAngulo >= 66) && (GrauAngulo <= 134) {
Direcao = "E"
}
if (GrauAngulo >= 135) && (GrauAngulo <= 165) {
Direcao = "SE"
}
if (GrauAngulo >= 166) && (GrauAngulo <= 205) {
Direcao = "S"
}
if (GrauAngulo >= 206) && (GrauAngulo <= 245) {
Direcao = "SW"
}
if (GrauAngulo >= 246) && (GrauAngulo <= 295) {
Direcao = "W"
}
if (GrauAngulo >= 296) && (GrauAngulo <= 325) {
Direcao = "NW"
}
// FILTRA POSIÇÕES COM COORDENADAS IGUAIS OU MAIORES QUE ZERO, NO BRASIL
//SÓ EXISTEM COORDENADAS NEGATIVAS. EVITANDO POSIÇÕES INDESEJADAS LÁ NA ÁFRICA/INGLATERRA
if (funcoes_gerais.StrToFloat(Latitude) >= 0) || (funcoes_gerais.StrToFloat(Longitude) >= 0) {
continue
}
// FILTRA POSIÇÕES COM COORDENADAS IGUAIS OU MAIORES QUE ZERO, NO BRASIL
//SÓ EXISTEM COORDENADAS NEGATIVAS. EVITANDO POSIÇÕES INDESEJADAS LÁ NA ÁFRICA/INGLATERRA
//PEGA O ID DO VEÍCULO----------------------------------------------------------
err = db.QueryRow("SELECT IDVEICULO, REGISTRAEVENTOSENTRADAS, FILTROGPS FROM VWVEICULOSCLIENTE WHERE SERIEMODULO = ?", SerieModulo).Scan(&IdVeiculo, &RegistraEventosEntradas, &FiltroGPS)
if err == sql.ErrNoRows {
continue
}
//PEGA O ID DO VEÍCULO----------------------------------------------------------
//PEGA O ID DO MOTORISTA CASO HAJA IDENTIFICACAO--------------------------------
if (strings.TrimSpace(ibutton) != "") && (strings.TrimSpace(ibutton) != "00000000000000") {
err = db.QueryRow("SELECT ID AS IDMOTORISTA FROM MOTORISTAS WHERE (IDELETRONICO = ?) OR (IDELETRONICORESERVA = ?)", ibutton, ibutton).Scan(&IdMotorista)
if err != nil {
IdMotorista = "0"
GeraLog(err.Error())
}
}
//PEGA O ID DO MOTORISTA CASO HAJA IDENTIFICACAO--------------------------------
//COMANDOS PARA O MÓDULO--------------------------------------------------------
sqlcmd = "SELECT BLOQUEIOSIRENEON,DESBLOQUEIOSIRENEOFF,BLOQUEIO,DESBLOQUEIO,SIRENEON,SIRENEOFF,RESET," +
"HORIMETRO,LIMPAMEMORIA,GETMOTORISTAS,COMANDOGENERICO FROM VWCOMANDOS WHERE SERIEMODULO = ?"
err = db.QueryRow(sqlcmd, SerieModulo).Scan(&SetBloqueioSireneOn, &SetDesbloqueioSireneOff, &SetBloqueio, &SetDesbloqueio, &SetSireneOn, &SetSireneOff, &SetReset, &SetHorimetro, &SetLimpaMemoria, &GetMotoristas, &SetComandoGenerico)
if err != nil {
GeraLog(err.Error())
} else {
if (SetBloqueioSireneOn == "1") && (funcoes_gerais.StrToInt64(Velocidade) <= 30) {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Enable1")
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Enable2")
}
if SetDesbloqueioSireneOff == "1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Disable1")
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Disable2")
}
if (SetBloqueio == "1") && (funcoes_gerais.StrToInt64(Velocidade) <= 30) {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Enable1")
}
if SetDesbloqueio == "1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Disable1")
}
if SetSireneOn == "1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Enable2")
}
if SetSireneOff == "1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Disable2")
}
if SetReset == "1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;Reboot")
}
if SetHorimetro != "-1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;SetHMeter="+SetHorimetro)
}
if SetLimpaMemoria == "1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;EraseAll")
}
if GetMotoristas == "1" {
enviaUDP(ServerConn, addr, Protocolo+"HGD;"+SerieModulo+";02;ALL")
}
if SetComandoGenerico != "-1" {
enviaUDP(ServerConn, addr, Protocolo+"CMD;"+SerieModulo+";02;"+SetComandoGenerico)
}
}
//COMANDOS PARA O MÓDULO--------------------------------------------------------
//EM CASO DE ALERTA, INSERE NO REGISTRO DE ALERTAS ENVIO DO SMS E RELATÓRIO-----
if TipoMsg == Protocolo+"ALT" {
var EventoAlerta string
var TipoRelatorioAlerta string
switch funcoes_gerais.StrToInt64(AlertID) {
case 01:
{
RegistraAlerta = true
EventoAlerta = "VELOCIDADE MÁXIMA EXCEDIDA."
TipoRelatorioAlerta = "3"
}
case 03:
{
RegistraAlerta = true
EventoAlerta = "ANTENA GPS DESCONECTADA."
TipoRelatorioAlerta = "4"
}
case 16:
{
RegistraAlerta = true
EventoAlerta = "ENTROU EM COLISAO."
TipoRelatorioAlerta = "7"
}
case 41:
{
RegistraAlerta = true
EventoAlerta = "FALHA NA ALIMENTACAO PRINCIPAL."
TipoRelatorioAlerta = "6"
}
case 45:
{
RegistraAlerta = true
EventoAlerta = "BATERIA INTERNA DE BACKUP REMOVIDA."
TipoRelatorioAlerta = "5"
}
case 59:
{
RegistraAlerta = true
EventoAlerta = "MOTORISTA IDENTIFICADO."
TipoRelatorioAlerta = "8"
}
}
if RegistraAlerta == true {
LocalizacaoAlerta = RetornaEndereco(Latitude, Longitude)
sqlcmd = " INSERT INTO REGISTROSALERTAS (IDVEICULO, IDMOTORISTA, DATAHORA, EVENTO, LOCALIZACAO, TIPORELATORIO, ALERTAENVIADO, VELOCIDADE, MOVENDO) " +
" VALUES (" + IdVeiculo + ", " + IdMotorista + ", CONVERT(DATETIME, '" + DataHoraGPS.Format("2006-01-02 15:04:05") + ".000', 121), '" + EventoAlerta + "', '" + LocalizacaoAlerta + "', " + TipoRelatorioAlerta + ", 0, '" + Velocidade + "', '" + Movendo + "') "
stmt, err = db.Prepare(sqlcmd)
defer stmt.Close()
if err != nil {
GeraLog("Registros Alertas,erro prepare: " + err.Error())
continue
}
sqlres, err = stmt.Exec()
if err != nil {
GeraLog("Registros Alertas,erro stmt.Exec(): " + err.Error())
continue
}
rowCnt, err = sqlres.RowsAffected()
if err != nil {
GeraLog("Registros Alertas; Erro ao tentar inserir. Registros Afetados: " + strconv.FormatInt(rowCnt, 10) + ".\r\n" + err.Error())
continue
}
}
}
//EM CASO DE ALERTA, INSERE NO REGISTRO DE ALERTAS ENVIO DO SMS E RELATÓRIO-----
//PEGA ULTIMA POSICAO OU REGISTRA O MODULO CASO NAO SEJA ENCONTRADO-------------
if ModuloNaoRegistrado(SerieModulo) {
ArrUltimaPosicao = append(ArrUltimaPosicao, TUltimaPosicao{funcoes_gerais.StrToFloat(Latitude), funcoes_gerais.StrToFloat(Longitude), SerieModulo})
} else {
UltimaPosicao = RetornaUltimaPosicao(SerieModulo)
PosicaoAtual = TPonto{funcoes_gerais.StrToFloat(Latitude), funcoes_gerais.StrToFloat(Longitude)}
if DentroPerimetroUltimaPosicao(UltimaPosicao, PosicaoAtual) || ((FiltroGPS == "1") && (Ignicao == "0")) {
Latitude = funcoes_gerais.FloatToStr(UltimaPosicao.Lat)
Longitude = funcoes_gerais.FloatToStr(UltimaPosicao.Lng)
}
AtualizaUltimaPosicao(funcoes_gerais.StrToFloat(Latitude), funcoes_gerais.StrToFloat(Longitude), SerieModulo)
}
//PEGA ULTIMA POSICAO OU REGISTRA O MODULO CASO NAO SEJA ENCONTRADO-------------
var Modelo string
if Protocolo == "SA200" {
Modelo = "STT2XX"
}
if Protocolo == "ST300" {
Modelo = "STT3XX"
}
//INSERE NA TABELA DE ATUALZACOES-----------------------------------------------
sqlcmd = " INSERT INTO ATUALIZACOES (STATUSPOSICAO, TIPOMSG, STATUSGPS, DATAHORA, DATAHORAGPS, LONGITUDE, LATITUDE, VELOCIDADE, IDMODULO, IGNICAO, ANTIFURTO, SAIDAS1, SAIDAS2, PANICO, ENTRADAS1, ENTRADAS2, ENTRADAS3, ENTRADAS4, SAIDAS3, SAIDAS4, DIRECAO, VELOCIDADEMAXIMAEXCEDIDA, BATERIACARREGANDO, FALHABATERIAINTERNA, FALHAALIMENTACAOPRINCIPAL, MOVENDO, TENSAO, HODOMETRO, HORIMETRO, RPM, INDICEPOSICAOMXT, MODELO, IDMOTORISTA) VALUES ('" + StatusPosicao + "', '4', '" + GPSValido + "', CONVERT(DATETIME, '" + DataHora.Format("2006-01-02 15:04:05") + ".000', 121), CONVERT(DATETIME, '" + DataHoraGPS.Format("2006-01-02 15:04:05") + ".000', 121), '" + Longitude + "', '" + Latitude + "', '" + Velocidade + "', " + IdModulo + ", '" + Ignicao + "', '" + Antifurto + "', '" + Saida1 + "', '" + Saida2 + "', '" + Panico + "', '" + Entrada1 + "', '" + Entrada2 + "', '" + Entrada3 + "', '" + Entrada4 + "', '" + Saida3 + "', '" + Saida4 + "', '" + Direcao + "', '" + VelocidadeMaximaExcedida + "', '" + BateriaCarregando + "', '" + FalhaBateriaInterna + "', '" + FalhaAlimentacaoPrincipal + "', '" + Movendo + "', '" + Tensao + "', " + Hodometro + ", " + Horimetro + ", " + Rpm + ", '0', '" + Modelo + "', " + IdMotorista + ") "
stmt, err = db.Prepare(sqlcmd)
defer stmt.Close()
if err != nil {
GeraLog("Insert Atualizacoes; erro prepare: " + err.Error())
continue
}
sqlres, err = stmt.Exec()
if err != nil {
GeraLog("Insert Atualizacoes; erro stmt.Exec(): " + err.Error())
GeraLog(sqlcmd)
continue
}
rowCnt, err = sqlres.RowsAffected()
if err != nil {
GeraLog("Erro ao tentar inserir. Registros Afetados: " + strconv.FormatInt(rowCnt, 10) + ".\r\n" + err.Error())
}
//INSERE NA TABELA DE ATUALZACOES-----------------------------------------------
} //FIM if (TipoMsg == Protocolo+"STT") || (TipoMsg == Protocolo+"ALT") {........
if (TipoMsg == Protocolo+"CMD") || ((TipoMsg == Protocolo+"HGD") && (Dados[1] == "Res")) { //ACK vinda do rastreador
//RECEBEU CONFIRMAÇÃO DO MÓDULO, ENTÃO RESETA TODOS OS COMANDOS SETANDO "0" E SETA RESPOSTA = "1"-----
sqlcmd = " UPDATE COMANDOS SET COMANDOGENERICO='-1', GETMOTORISTAS=0, BLOQUEIO=0, BLOQUEIOPROGRESSIVO=0, BLOQUEIOSIRENEON=0, DESBLOQUEIO=0, DESBLOQUEIOSIRENEOFF=0, SIRENEON=0, SIRENEOFF=0, NUM1=0, NUM2=0, NUM3=0, NUM4=0, LEDRED=0, LEDGREEN=0, LEDX=0, " +
" RESPOSTA=1, INTERVALO=0, PANICO=0, RESET=0, DESATIVAFILTROGPS=0, ATIVAFILTROGPS=0, POWEROFF=0, LIMPAMEMORIA=0, HORIMETRO='-1', CONFIGIP='-1' " +
" WHERE IDMODULO = (SELECT ID FROM MODULOS WHERE SERIEMODULO = ?) "
stmt, err = db.Prepare(sqlcmd)
defer stmt.Close()
if err != nil {
GeraLog("Update reset comandos; erro prepare: " + err.Error())
continue
}
sqlres, err = stmt.Exec(SerieModulo)
if err != nil {
GeraLog("Update reset comandos; erro stmt.Exec(): " + err.Error())
GeraLog(sqlcmd)
continue
}
rowCnt, err = sqlres.RowsAffected()
if err != nil {
GeraLog("Erro ao tentar efeturar o UPDATE na tabela comandos. Registros Afetados: " + strconv.FormatInt(rowCnt, 10) + ".\r\n" + err.Error())
}
//RECEBEU CONFIRMAÇÃO DO MÓDULO, ENTÃO RESETA TODOS OS COMANDOS SETANDO "0" E SETA RESPOSTA = "1"-----
}
//debug.FreeOSMemory() //GARBAGE COLLECT
} //FIM LOOP SERVICO UDP..........................
}
The deferred methods in the infinite for
loop will never run as the function never exits.
I see line 520: stmt, err := db.Prepare(sqlcmd)
. But nowhere are you calling Close() on stmt. You must call Close() according to the documentation of DB.Prepare().
On lines 572 and 602 you call defer stmt.Close()
. Deferred statements are only run when the function it was called in returns. Because main never returns the deferred statements are never executed! I believe this is the root cause of your runaway memory issues.
I also see a potential SQL injection attack on line 570 sqlcmdatualizacao := " INSERT INTO ATUALIZACOES...
. Perhaps use a prepared statement here as well.
You have many “helper” functions that just hide a tiny bit of boilerplate. Most of them are unnecessary and make the code more difficult to read. Remove them.
At the same time the enormous main()
function desperately needs refactoring into smaller pieces. This is very different from what you’ve done with the “helper” functions. Put each labeled section into a new function that takes parameters and returns a result (don’t use globals!, pass only the values that section needs to execute).
Here’s a list of changes I would make to this code:
AngleToDirection(angle int) string
. This is different from your “helper” functions because it makes decisions, it doesn’t just hide boilerplate.Just these refactorings will fix the memory issues you’re encountering due to defers never running. It will also be easier to debug future problems.
I did all my friends told me on here,and it still increases memory usage… I really dunno nothing else to do in order to solve that problem… Too bad…
you can try to identify the sequence that consume memory with runtime package by inserting and logging snippets like in the following example, after your queries in the loop
package main
import (
"log"
"runtime"
)
func main() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
log.Println(m.Alloc)
s := make([]byte, 1024*1024)
s[0] = 0
runtime.ReadMemStats(&m)
log.Println(m.Alloc)
}
also,see here a more detailed example.
in this way i guess you should see after some iterations what sequence increase the memory more than is expected…
This is th perfect use case for th execution tracer. Trace your program then you’ll be able to see the increase in heap and to trace it to the code running at the time.
Hey Dave, you mean using go tool trace
? I’m also interested how can i see a memory leak generated by a specific piece of code but the result of trace in browser seems to be only a statistics of resources on a period of time
George, I did it and what I saw is after every db.QueryRow() memory usage increases but I couldn’t find any method de close that row… Is there any way to close it?
Tnx.
Yup, the trace tool. If you record a profile of the entire operation of your program you should be able to see an increase in the heap, or number of goroutines, over time.
the Row.Scan function calls rows.Close() internally: https://golang.org/src/database/sql/sql.go#L1891
So as long as you’re actually calling Scan on the value returned by QueryRow, it should close the result set.
@leogazio, i didn’t used the db.QueryRow but db.Query and not in a loop. try using db.Query instead and see if you obtain the same behaviour. also you can try (as @infogulch said that db.QueryRaw close the result set) to insert a short delay after the db.QueryRow to wait for the command to complete.
@dfc, thanks. i will consider studying the tracer.
But I can’t do it, can’t put delay inside that loop, because that receives lots of UDP datagrams, if I put a 1 second delay and a hundred clients send datagrams at the same time, the last one will have to wait about 100 secs, this way that specific client won’t receive its ACK, and will start work badly…
Yeah I saw it now in the sql.go code you gave me but, why most of the examples on the web use defer rows.Close()? If it closes byh itself…
yeap, i think is not realy a good ideea to handle the datagrams on the fly
because you need to be quick. i think that a better approach is serializing
the requests in messages queues and handle them afterward because db
operations are slower than receiving packets and also can have errors.
You misread.
When you call DB.QueryRow()
, calling Scan()
on the result will automatically close it.
When you call DB.Query
, you must call Close()
yourself. This is often done with defer
. For defer
to work the function in which it appears must return.