I've been using Valgrind to look for memory leaks in my code, and while no memory leaks are being found, some errors are reported all of them originating at a single function/class method:
==17043== ERROR SUMMARY: 10100 errors from 3 contexts (suppressed: 0 from 0)
==17043==
==17043== 100 errors in context 1 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043== at 0x5441DA2: send (send.c:28)
==17043== by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x404F1C: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== Address 0x7feffff61 is on thread 1's stack
==17043== Uninitialised value was created by a stack allocation
==17043== at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==
==17043==
==17043== 100 errors in context 2 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043== at 0x5441DA2: send (send.c:28)
==17043== by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x404E8A: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== Address 0x7feffff61 is on thread 1's stack
==17043== Uninitialised value was created by a stack allocation
==17043== at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==
==17043==
==17043== 9900 errors in context 3 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043== at 0x5441DA2: send (send.c:28)
==17043== by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x404EE8: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== Address 0x7feffff61 is on thread 1's stack
==17043== Uninitialised value was created by a stack allocation
==17043== at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==
==17043== ERROR SUMMARY: 10100 errors from 3 contexts (suppressed: 0 from 0)
The sendMsg(const char _type, const double _value), that the errors are pointing at, is part of unix_socket class:
//...
typedef struct{
char type;
double value;
} MESSAGE;
//...
int unix_socket::sendMsg(const char _type, const double _value){
MESSAGE msg;
msg.type=_type;
msg.value=_value;
int n = send(client_sock, &msg, sizeof(msg), 0);
if (n < 0) {
perror("send");
return -1;
}
c_sent=msg.type;
v_sent=msg.value;
return 0;
}
I don't see what is the problem. Where exactly are the uninitialized values? Or should I just ignore the errors reported by Valgrind?
Look at the MESSAGE struct:
typedef struct{
char type;
double value;
} MESSAGE;
Due to data structure alignment, value's address may be forced to align to address of a multiple of word size. Therefore, several unused bytes is padded between MESSAGE::type and MESSAGE::value. Those are the bytes which weren't initialized and thus reported by Valgrind.
As a workaround, you could force initializing the whole struct by memset().
MESSAGE msg;
memset(&msg, 0, sizeof(MESSAGE));
msg.type=_type;
msg.value=_value;
Although #timrau has described quite correctly what the core problem is here (alignment/packing), I'm not a fan of the proposed solution.
You have described a MESSAGE in your code as consisting of a char and a double. The size of the actual data structure in memory however is not sizeof(char) + sizeof(double), and that is the core problem.
The proposed solution suggests simply clearing out all of the bits of the MESSAGE structure before filling in the important bits. The problem I have with that is both a semantic one a technical one -- the size of the data structure sent down the wire is not an accurate representation of what you modeled in the code. In other words, you're not just sending a char and a double -- you're sending a char, a double and some other cruft (padding).
My suggestion is to get rid of the cruft and send only what you modeled in your code.
There is no direct support in C++ to turn off alignment and padding, but all compilers I'm aware of provide a simple mechanism to align data structures to N bytes:
#pragma pack (push, 1)
typedef struct{
char type;
double value;
} MESSAGE;
#pragma pack (pop)
This will make the MESSAGE data structure exactly what you've modeled in your code, with no padding. Doing this makes the memset unnecesarry, and you'll send exactly sizeof(char) + sizeof(double) bytes down the wire.
Related
I'm a new C++ coder and met a problem.
Please view the following code as an example:
#include <iostream>
#include <vector>
#include <thread>
class student{
public:
std::string name;
int id;
};
void foo(){
int k = 1;
std::cout<<"thread a"<<std::endl;
return;
}
void foo2(){
int k = 1;
std::cout<<"thread b"<<std::endl;
return;
}
void foo3(){
std::thread a(foo);
std::thread b(foo2);
a.detach();
b.detach();
return;
}
int main(){
foo3();
return 0;
}
That's an example code. I want two threads running independently and release memory after each one ends. I use valgrind to check memory leak. It shows an error like this:
==63346== Memcheck, a memory error detector
==63346== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==63346== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==63346== Command: ./a.out
==63346==
==63346==
==63346== HEAP SUMMARY:
==63346== in use at exit: 608 bytes in 4 blocks
==63346== total heap usage: 5 allocs, 1 frees, 73,312 bytes allocated
==63346==
==63346== 288 bytes in 1 blocks are possibly lost in loss record 3 of 4
==63346== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==63346== by 0x40147D9: calloc (rtld-malloc.h:44)
==63346== by 0x40147D9: allocate_dtv (dl-tls.c:375)
==63346== by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==63346== by 0x4B4D834: allocate_stack (allocatestack.c:430)
==63346== by 0x4B4D834: pthread_create##GLIBC_2.34 (pthread_create.c:647)
==63346== by 0x494A388: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==63346== by 0x1095B9: std::thread::thread<void (&)(), , void>(void (&)()) (in /home/alan/Avionics/test/a.out)
==63346== by 0x10935C: foo3() (in /home/alan/Avionics/test/a.out)
==63346== by 0x109400: main (in /home/alan/Avionics/test/a.out)
==63346==
==63346== 288 bytes in 1 blocks are possibly lost in loss record 4 of 4
==63346== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==63346== by 0x40147D9: calloc (rtld-malloc.h:44)
==63346== by 0x40147D9: allocate_dtv (dl-tls.c:375)
==63346== by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==63346== by 0x4B4D834: allocate_stack (allocatestack.c:430)
==63346== by 0x4B4D834: pthread_create##GLIBC_2.34 (pthread_create.c:647)
==63346== by 0x494A388: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==63346== by 0x1095B9: std::thread::thread<void (&)(), , void>(void (&)()) (in /home/alan/Avionics/test/a.out)
==63346== by 0x109372: foo3() (in /home/alan/Avionics/test/a.out)
==63346== by 0x109400: main (in /home/alan/Avionics/test/a.out)
==63346==
==63346== LEAK SUMMARY:
==63346== definitely lost: 0 bytes in 0 blocks
==63346== indirectly lost: 0 bytes in 0 blocks
==63346== possibly lost: 576 bytes in 2 blocks
==63346== still reachable: 32 bytes in 2 blocks
==63346== suppressed: 0 bytes in 0 blocks
==63346== Reachable blocks (those to which a pointer was found) are not shown.
==63346== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==63346==
==63346== For lists of detected and suppressed errors, rerun with: -s
==63346== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
If i replace detach() by join(), there's no memory leak, I'm a little confused. Does anyone can give me some advice? Thanks a lot!
You need to make your main wait until the threads have finished running (or at least that they won't access any global objects after). If you don't make sure of that, not only will you have memory leaks, you may also have undefined behavior.
join does exactly make sure of that. The thread calling it will wait until the thread on which join is called finishes.
On the other hand detach is used to when you don't want to keep the std::thread object around to call join on it, while still having the thread function continue to run. If you detach a thread you need to use some other synchronization mechanism outside the join mechanism to make sure that main doesn't exit while the threads are still doing work (or at least accessing global objects).
There is rarely a need to detach a thread. Making it work is complicated. You don't need to do that.
Instead store the std::thread object somewhere and call join on it when you want to wait for your threads to end, at latest before main returns. That should be the default approach if you don't have a good reason to not use it. If you are a beginner, then you can forget about detach for now.
I've tried to change the code to do what I want in different ways but doesn't seem to fix that Valgrind error.
Cadena::Cadena(unsigned tam, char c):s_(new char[tam+1]), tam_(tam)
{
//c is ' ' by default
memset(s_, c, tam+1);
s_[tam]='\0';
}
...
Cadena& Cadena::substr(unsigned i, unsigned tam) const
{
if(i>=tam_||i+tam>tam_) throw out_of_range("Posicion indicada fuera de rango");
Cadena* subCad=new Cadena(tam);
strncpy(subCad->s_, &s_[i], tam);
return *subCad;
}
==9669== Invalid write of size 1
==9669== at 0x1390CC: Cadena::Cadena(unsigned int, char) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x13972B: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x12D436: test_cadena(_fctkern_t*) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x137D42: main (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== Address 0x105bc176f is not stack'd, malloc'd or (recently) free'd
==9669==
==9669==
==9669== Process terminating with default action of signal 11 (SIGSEGV)
==9669== Access not within mapped region at address 0x105BC176F
==9669== at 0x1390CC: Cadena::Cadena(unsigned int, char) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x13972B: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x12D436: test_cadena(_fctkern_t*) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x137D42: main (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== If you believe this happened as a result of a stack
==9669== overflow in your program's main thread (unlikely but
==9669== possible), you can try to increase the size of the
==9669== main thread stack using the --main-stacksize= flag.
==9669== The main thread stack size used in this run was 8388608.
Another way:
Cadena& Cadena::substr(unsigned i, unsigned tam) const
{
if(i>=tam_||i+tam>tam_) throw out_of_range("Posicion indicada fuera de rango");
char res[tam+1];
strncpy(res, s_+i, tam);
res[tam]='\0';
Cadena* subCad=new Cadena(tam);
return *subCad;
}
==17029== Invalid write of size 1
==17029== at 0x4C3304C: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17029== by 0x13979E: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==17029== Address 0x1fff001000 is not stack'd, malloc'd or (recently) free'd
==17029==
==17029==
==17029== Process terminating with default action of signal 11 (SIGSEGV)
==17029== Access not within mapped region at address 0x1FFF001000
==17029== at 0x4C3304C: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17029== by 0x13979E: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==17029== If you believe this happened as a result of a stack
==17029== overflow in your program's main thread (unlikely but
==17029== possible), you can try to increase the size of the
==17029== main thread stack using the --main-stacksize= flag.
==17029== The main thread stack size used in this run was 8388608.
I'm passing this test (test-P1-auto):
FCT_TEST_BGN(Cadena - Subcadena: tamanno mayor que longitud restante) {
const Cadena a("0123456789");
fct_chk_ex(out_of_range&, a.substr(9, 2));
}
FCT_TEST_END();
It returns a substring of two elements following the number 8. It's not possible as it throws out_of_range, so the test is OK. But when I use Valgrind, it's giving me those errors and I've been stuck here for hours.
Private part of my class Cadena:
private:
char* s_;
unsigned int tam_;
Sorry for the mistake guys, but as #Some programmer dude commented I didn't put the flag -g on my makefile that allows valgrind to tell me wich lines make the errors. Actually that wasn't the right test, it was the next one:
FCT_TEST_BGN(Cadena - Subcadena: tamanno negativo) {
const Cadena a("0123456789");
fct_chk_ex(out_of_range&, a.substr(9, -1));
}
FCT_TEST_END();
As I can see here Signed to unsigned conversion in C - is it always safe?, there's no way to get a negative value as unsigned and expect the sign "just to be removed". I solved it by changing it to int and checking inside the function if it's negative.
Thanks everyone for your help.
I want to understand the valgrind log messages and use the following code
#include <iostream>
int main()
{
int numbers[] = {1,2,3,4,5,6,7,8,9,10};
int length = sizeof(numbers) / sizeof(numbers[0]);
std::cout << "length: " << length << std::endl;
for (int i = 0; i < length + 10; ++i)
{
int number = numbers[i];
if (number > 5)
{
std::cout << number << " is greater than 5" << std::endl;
} else {
std::cout << number << " is less or equal 5" << std::endl;
}
}
}
to produce uninitialised values. If I run the program in valgrind I don't receive a corresponding message. If I run the for-loop to length + 10 valgrind detects uninitialised values.
Why does valgrind detect the unitialised values only so late?
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x108A3C: main (arrays.cpp:11)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x4F43C0A: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Use of uninitialised value of size 8
==2484== at 0x4F4370E: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F43C33: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x4F4371B: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F43C33: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
==2484==
==2484== Conditional jump or move depends on uninitialised value(s)
==2484== at 0x4F43C66: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x4F501A4: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==2484== by 0x108A85: main (arrays.cpp:15)
==2484== Uninitialised value was created by a stack allocation
==2484== at 0x51E6ABB: (below main) (libc-start.c:137)
EDIT: I changed the code. THis is the whole code i used.
compile: g++ -c -g3 arrays.cpp arrays.cpp
valgrind: valgrind --tool=memcheck --track-origins=yes --num-callers=100 --log-file=uv_log.txt ./arrays
EDIT 2:
length: 10
1 is less or equal 5
2 is less or equal 5
3 is less or equal 5
4 is less or equal 5
5 is less or equal 5
6 is greater than 5
7 is greater than 5
8 is greater than 5
9 is greater than 5
10 is greater than 5
-882498304 is less or equal 5
-188984184 is less or equal 5
1084208 is greater than 5
0 is less or equal 5
85879703 is greater than 5
0 is less or equal 5
0 is less or equal 5
You don't actually check for uninitialized access. You check for index out of bounds access. In your case, the out of bounds access is on the stack, so you access some memory, which is on the stack. And you're lucky, because the whole accessed area is on the stack, so you don't get an invalid read. Your program reads some data of the stack, which happens to be initialized for the length+1 case (because there is some other thing written to it, for example, it can be function parameter, other local variable or the function's return address), so valgrind is not able to report any error.
But for the length+10 case, it is large enough to actually read from some uninitialized memory. And I bet, if you increase 10 to a much larger number, you'll get invalid read (which causes segmentation fault).
I have a C++ app and I know in advance that I am expecting around 1000 elements (sometimes few more) to store and process for hundreds of instances.
The issue is that the memory used by the process increases slowly but the memory of the server is overwhelmed in few hours.
I am using valgrind for detecting eventual memory leaks.
Edit
First thanks to all of you for the suggestions. I managed to solve many errors. I added virtual destructors to some classes and changed some pointers to boost::shared_ptr using reset to delete them. However I still have an increasing memory usage over the time.
The main parts of the app are as follows :
#ifdef GLOBAL
#define Global
#else
#define Global extern
#endif
typedef std::map<uint32_t, ResultStruct> ClassDResultMap ;
typedef std::map<uint32_t, ClassDResultMap > ClassCResultMap ;
typedef std::map<uint32_t, ClassCResultMap > ClassBResultMap ;
typedef std::map<uint32_t, ClassBResultMap > ClassAResultMap ;
Global ClassAResultMap classAresultmap;
ClassZero creates many ClassA
typedef std::map<uint32_t,ClassA*> classAMap;
classA_[aid] = new ClassA(io_service_, filename.c_str(), id, pri_queue_);
Inside ClassA, up to 3200 ClassB instance are created:
typedef std::map<uint32_t, boost::shared_ptr<ClassB >> classBMap ;
classBMap[aid].insert(std::pair<uint32_t, boost::shared_ptr<ClassB>>(bid, boost::make_shared<ClassB >(io_service_, pri_queue_, ...)));
Inside ClassB, up to 4 ClassC instances are created inside a ConfigMap struct having a member boost::shared_ptr<ClassC > classC_; :
typedef std::map<uint32_t, classCConfig> ConfigMap;
(ConfigMap::iterator)->second.classC_ = boost::make_shared<ClassC >(io_service_, pri_queue_, ...);
Inside ClassC, one ClassD is instantiated by ClassC constructor
ClassC::ClassC(...): ClassD(io_service_, pri_queue_,...),... { }
Then Inside ClassD, elements are processed and results are calculated every 10-30 seconds than stored in ClassDResultMap :
(ClassDResultMap::iterator)->second[results.stime] = results;
Finally, inside another class, ClassStorage, all the results in the global ClassAResultmap are saved into files and cleared :
std::ofstream res_stream_;
res_stream_ << "{ \"start\" : " << results_it->second.stime << ...;
(ClassDResultMap::iterator)->second.clear();
std::map<uint32_t, ClassDResultMap>().swap((ClassDResultMap::iterator)->second);
This what I get with Valgrind with 1 Class A : 8 ClassB : 32 class C/D
==9544== HEAP SUMMARY:
==9544== in use at exit: 25,817 bytes in 171 blocks
==9544== total heap usage: 148,771 allocs, 148,600 frees, 16,803,272 bytes allocated
==9544==
==9544== 1,216 bytes in 4 blocks are possibly lost in loss record 39 of 45
==9544== at 0x4C2677B: calloc (vg_replace_malloc.c:593)
==9544== by 0x40118A2: _dl_allocate_tls (in /lib64/ld-2.12.so)
==9544== by 0x5F971E8: pthread_create##GLIBC_2.2.5 (in /lib64/libpthread-2.12.so)
==9544== by 0x4E3ACC0: boost::thread::start_thread_noexcept() (in /usr/local/lib/libboost_thread.so.1.54.0)
==9544== by 0x45EE92: boost::thread::start_thread() (thread.hpp:180)
==9544== by 0x461429: boost::thread::thread<boost::_bi::bind_t<unsigned long, boost::_mfi::mf0<unsigned long, boost::asio::io_service>, boost::_bi::list1<boost::reference_wrapper<boost::asio::io_service> > >&>(boost::_bi::bind_t<unsigned long, boost::_mfi::mf0<unsigned long, boost::asio::io_service>, boost::_bi::list1<boost::reference_wrapper<boost::asio::io_service> > >&) (thread.hpp:267)
==9544== by 0x4605F7: boost::thread* boost::thread_group::create_thread<boost::_bi::bind_t<unsigned long, boost::_mfi::mf0<unsigned long, boost::asio::io_service>, boost::_bi::list1<boost::reference_wrapper<boost::asio::io_service> > > >(boost::_bi::bind_t<unsigned long, boost::_mfi::mf0<unsigned long, boost::asio::io_service>, boost::_bi::list1<boost::reference_wrapper<boost::asio::io_service> > >) (thread_group.hpp:78)
==9544== by 0x45CAC9: main (main.cpp:151)
==9544==
==9544== LEAK SUMMARY:
==9544== definitely lost: 0 bytes in 0 blocks
==9544== indirectly lost: 0 bytes in 0 blocks
==9544== possibly lost: 1,216 bytes in 4 blocks
==9544== still reachable: 24,601 bytes in 167 blocks
==9544== suppressed: 0 bytes in 0 blocks
==9544== Reachable blocks (those to which a pointer was found) are not shown.
==9544== To see them, rerun with: --leak-check=full --show-reachable=yes
==9544==
==9544== For counts of detected and suppressed errors, rerun with: -v
==9544== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
and the part of main.cpp which Valgrind complains about :
boost::asio::io_service work_io_service;
ClassZero manager(work_io_service);
boost::thread_group work_threads;
uint32_t workers = boost::thread::hardware_concurrency();
for (std::size_t i = 0; i != workers; ++i)
{
work_threads.create_thread(
boost::bind(&boost::asio::io_service::run, boost::ref(work_io_service)));
}
My issue is that in almost 20 minutes, the server memory (4GB ) increased from 3% to 17% and keeps going on. The process memory usage is increasing but stays below 4% !
I am trying to use C++11's std::tr1::shared_ptr to manage SDL_Surface pointers. Note, I am not using Boost. I have defined a deleter for the shared_ptr to use SDL_FreeSurface.
Declared like:
class Engine {
private:
std::tr1::shared_ptr<SDL_Surface> _scr;
std::tr1::shared_ptr<SDL_Surface> _bg;
Defined (in Engine's ctor) like:
_scr = std::tr1::shared_ptr<SDL_Surface>( SDL_SetVideoMode(Data::SCR_WIDTH,
Data::SCR_HEIGHT,
32, SDL_SWSURFACE),
SurfaceDeleter<SDL_Surface>());
_bg = std::tr1::shared_ptr<SDL_Surface>(IMG_Load(Data::IM_BACKGROUND),
SurfaceDeleter<SDL_Surface>());
The custom deleter:
template<typename T>
class SurfaceDeleter{
public:
void operator() (T*& d) const {
if(d){
SDL_FreeSurface(d);
}
}
};
The only object holding the shared_ptr is the Engine. The shared_ptr was used like so:
SDL_BlitSurface(_bg.get(), nullptr, _scr.get(), nullptr);
SDL_Flip(_scr.get());
Valgrind results:
==3648== 8 bytes in 2 blocks are definitely lost in loss record 16 of 292
==3648== at 0x402A018: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3648== by 0x431FBE0: strdup (in /lib/libc-2.14.1.so)
==3648== 1 bytes in 1 blocks are definitely lost in loss record 1 of 292
==3648== at 0x402A018: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3648== by 0x494A590: _XlcDefaultMapModifiers (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494A99A: XSetLocaleModifiers (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x4097CDB: ??? (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x4083868: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x40594D9: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x42C3212: (below main) (in /lib/libc-2.14.1.so)
==3648== 980 (68 direct, 912 indirect) bytes in 1 blocks are definitely lost in loss record 258 of 292
==3648== at 0x402A102: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3648== by 0x49402A6: ??? (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x49407A2: ??? (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494212F: ??? (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x49429BA: _XlcCreateLC (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x4965957: _XlcUtf8Loader (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494A793: _XOpenLC (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494A8F1: _XlcCurrentLC (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x4097CDB: ??? (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x4083868: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x40594D9: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x42C3212: (below main) (in /lib/libc-2.14.1.so)
Run valgrind with --track-origins=yes so it shows you where the leaked memory was allocated.
You might also want to use --leak-check=full and --leak-resolution=high (although the latter should be the default)