Too much memory usage. Appreccite any help [SOLVED]

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.

1 Like

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:

  • Instead of defining a large number of variables at the top of the loop, define a couple structs and use them to pass data between main and these new functions.
  • Separate the position/alert handler into its own function.
  • Separate the confirmation handler into its own function.
  • Put each of the protocol handlers into their own functions. (lines 137, 234)
  • Lines 347-370 should be a function 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.

1 Like

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…

1 Like

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.

1 Like

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 :confused:

1 Like

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.

1 Like

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.

1 Like

@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.

1 Like

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.