heap_dump 0.0.27 → 0.0.28
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -3
- data/ext/heap_dump/heap_dump.c +70 -6
- data/ext/heap_dump/ruby_io.h +2 -2
- data/lib/heap_dump/version.rb +1 -1
- metadata +3 -3
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# HeapDump
|
2
2
|
|
3
|
-
Low-level ruby heap memory dump - including data and code references.
|
4
|
-
|
3
|
+
Low-level ruby heap memory dump - including data and code references, useful for finding leaks.
|
4
|
+
Has no performance overhead while not active, so can be used in production environment.
|
5
5
|
|
6
|
+
Originally written across ruby 1.9.2-p290 data structures.
|
6
7
|
Does work on other 1.9.2s and 1.9.3, but not well-tested yet(output is not proven to be as full etc.).
|
7
8
|
|
8
9
|
Currently is under development and output format may differ.
|
@@ -35,6 +36,10 @@ Json contains one object per line, thus can be easily grepped.
|
|
35
36
|
|
36
37
|
### Injecting into live process via GDB
|
37
38
|
|
39
|
+
For long-running applications common and recommended usecase is to have some kind of custom action or signal handler in app itself that invokes dump.
|
40
|
+
|
41
|
+
But also dump can be invoked from gdb.
|
42
|
+
|
38
43
|
run gdb
|
39
44
|
|
40
45
|
```bash
|
@@ -51,7 +56,8 @@ call heapdump_dump("mydump.json")
|
|
51
56
|
|
52
57
|
or `call heapdump_dump(0)`, filename defaults to dump.json.
|
53
58
|
|
54
|
-
Note that ruby
|
59
|
+
Note that yajl-ruby gem (and heap_dump itself) should be available to process this being injected into.
|
60
|
+
Also on rare ocassions process(for example if gdb attached while a signal/gc) may crash after and even during dumping, so safer way is to embed it in advance, there's no performance overhead.
|
55
61
|
|
56
62
|
### Importing dump in MongoDB
|
57
63
|
|
data/ext/heap_dump/heap_dump.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "ruby.h"
|
2
|
+
#include "ruby/encoding.h"
|
2
3
|
#include <stdlib.h>
|
3
4
|
#include <stdio.h>
|
4
5
|
|
@@ -107,8 +108,8 @@ static void flush_yajl(walk_ctx_t *ctx){
|
|
107
108
|
|
108
109
|
static inline int is_in_heap(void *ptr, void* osp);
|
109
110
|
|
110
|
-
static inline const char*
|
111
|
-
switch(
|
111
|
+
static inline const char* rb_type_str(int type){
|
112
|
+
switch(type){
|
112
113
|
#define T(t) case t: return #t;
|
113
114
|
T(T_NONE); T(T_NIL);
|
114
115
|
T(T_OBJECT); T(T_CLASS); T(T_ICLASS); T(T_MODULE);
|
@@ -124,9 +125,16 @@ static inline const char* rb_builtin_type(VALUE obj){
|
|
124
125
|
T(T_NODE); // code?
|
125
126
|
T(T_ZOMBIE);
|
126
127
|
#undef T
|
128
|
+
default:
|
129
|
+
return "_unknown_type_";
|
127
130
|
}
|
128
131
|
}
|
129
132
|
|
133
|
+
static inline const char* rb_builtin_type(VALUE obj){
|
134
|
+
//NOTE: only for heap objects, on embedded use (TYPE(...))
|
135
|
+
return rb_type_str(BUILTIN_TYPE(obj));
|
136
|
+
}
|
137
|
+
|
130
138
|
#define true 1
|
131
139
|
#define false 0
|
132
140
|
|
@@ -185,7 +193,14 @@ static void yg_id1(VALUE obj, walk_ctx_t* ctx){
|
|
185
193
|
if(BUILTIN_TYPE(obj) == T_STRING && (!(RBASIC(obj)->flags & RSTRING_NOEMBED))){
|
186
194
|
//printf("embedded string\n");
|
187
195
|
//yajl_gen_null(ctx->yajl);
|
188
|
-
|
196
|
+
|
197
|
+
if(rb_enc_get_index(obj) == rb_usascii_encindex())
|
198
|
+
yg_rstring(obj);
|
199
|
+
else{
|
200
|
+
//FIXME: convert encoding/safe syms etc?
|
201
|
+
//yg_cstring("(encoded string)");
|
202
|
+
yg_rstring(obj);
|
203
|
+
}
|
189
204
|
return;
|
190
205
|
}
|
191
206
|
|
@@ -444,7 +459,36 @@ static inline void dump_node(NODE* obj, walk_ctx_t *ctx){
|
|
444
459
|
|
445
460
|
static int
|
446
461
|
dump_keyvalue(st_data_t key, st_data_t value, walk_ctx_t *ctx){
|
447
|
-
|
462
|
+
if ((VALUE)key == Qundef){
|
463
|
+
printf("undef key!\n");
|
464
|
+
// return ST_CONTINUE;
|
465
|
+
}
|
466
|
+
|
467
|
+
if(!key || (VALUE)key == Qnil){
|
468
|
+
yg_cstring("___null_key___"); //TODO: just ""?
|
469
|
+
} else {
|
470
|
+
//TODO: keys must be strings
|
471
|
+
const int type = TYPE(key);
|
472
|
+
if(type == T_SYMBOL || type == T_STRING && (!(RBASIC(key)->flags & RSTRING_NOEMBED)))
|
473
|
+
yg_id((VALUE)key);
|
474
|
+
else
|
475
|
+
{
|
476
|
+
char buf[128];
|
477
|
+
buf[sizeof(buf)-1] = 0;
|
478
|
+
switch(type){
|
479
|
+
case T_FIXNUM:
|
480
|
+
snprintf(buf, sizeof(buf)-1, "%d", FIX2INT(key));
|
481
|
+
break;
|
482
|
+
case T_FLOAT:
|
483
|
+
snprintf(buf, sizeof(buf)-1, "%lg", NUM2DBL(key));
|
484
|
+
break;
|
485
|
+
default:
|
486
|
+
snprintf(buf, sizeof(buf)-1, "__id_%ld", NUM2LONG(rb_obj_id(key)));
|
487
|
+
break;
|
488
|
+
}
|
489
|
+
yg_cstring(buf);
|
490
|
+
}
|
491
|
+
}
|
448
492
|
yg_id((VALUE)value);
|
449
493
|
return ST_CONTINUE;
|
450
494
|
}
|
@@ -512,7 +556,7 @@ static int dump_iv_entry(ID key, VALUE value, walk_ctx_t *ctx){
|
|
512
556
|
if(key_str)
|
513
557
|
yg_cstring(key_str);
|
514
558
|
else{
|
515
|
-
printf("Null key! %d\n", key);
|
559
|
+
// printf("Null key! %d\n", key);
|
516
560
|
yg_cstring("___null_key___");
|
517
561
|
//yg_null();
|
518
562
|
}
|
@@ -935,13 +979,32 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
|
|
935
979
|
break;
|
936
980
|
case T_STRING:
|
937
981
|
//TODO: limit string len!
|
982
|
+
{
|
983
|
+
int enc_i = rb_enc_get_index(obj);
|
984
|
+
rb_encoding* enc = rb_enc_from_index(enc_i);
|
985
|
+
if(enc){
|
986
|
+
ygh_cstring("encoding", enc->name);
|
987
|
+
}
|
988
|
+
//FIXME: convert encoding and dump?
|
989
|
+
//if(enc_i == rb_usascii_encindex())
|
990
|
+
//this produces warnings on dump read, but recoverable
|
938
991
|
ygh_string("val", RSTRING_PTR(obj), (unsigned int)RSTRING_LEN(obj));
|
992
|
+
}
|
939
993
|
break;
|
940
994
|
case T_SYMBOL:
|
941
995
|
ygh_cstring("val", rb_id2name(SYM2ID(obj)));
|
942
996
|
break;
|
943
997
|
case T_REGEXP:
|
998
|
+
{
|
999
|
+
int enc_i = rb_enc_get_index(obj);
|
1000
|
+
rb_encoding* enc = rb_enc_from_index(enc_i);
|
1001
|
+
if(enc){
|
1002
|
+
ygh_cstring("encoding", enc->name);
|
1003
|
+
}
|
1004
|
+
//FIXME: encodings?
|
1005
|
+
// if(enc_i == rb_usascii_encindex())
|
944
1006
|
ygh_string("val", RREGEXP_SRC_PTR(obj), (unsigned int)RREGEXP_SRC_LEN(obj));
|
1007
|
+
}
|
945
1008
|
break;
|
946
1009
|
// T(T_MATCH);
|
947
1010
|
|
@@ -1494,7 +1557,7 @@ void heapdump_dump(const char* filename){
|
|
1494
1557
|
|
1495
1558
|
dump_machine_context(ctx);
|
1496
1559
|
flush_yajl(ctx);
|
1497
|
-
fprintf(ctx->file, "\n");
|
1560
|
+
// fprintf(ctx->file, "\n");
|
1498
1561
|
|
1499
1562
|
struct gc_list *list;
|
1500
1563
|
/* mark protected global variables */
|
@@ -1521,6 +1584,7 @@ void heapdump_dump(const char* filename){
|
|
1521
1584
|
|
1522
1585
|
yajl_gen_map_close(ctx->yajl); //id:roots
|
1523
1586
|
flush_yajl(ctx);
|
1587
|
+
fprintf(ctx->file, "\n");
|
1524
1588
|
|
1525
1589
|
//now dump all live objects
|
1526
1590
|
printf("starting objspace walk\n");
|
data/ext/heap_dump/ruby_io.h
CHANGED
@@ -11,8 +11,8 @@ typedef struct {
|
|
11
11
|
|
12
12
|
//#include "encoding.h" // and this also (rb_encoding + rb_econv_t)
|
13
13
|
//FIXME: nasty:
|
14
|
-
typedef int rb_encoding;
|
15
|
-
typedef struct rb_econv rb_econv_t;
|
14
|
+
// typedef int rb_encoding;
|
15
|
+
// typedef struct rb_econv rb_econv_t;
|
16
16
|
|
17
17
|
typedef struct rb_io_t {
|
18
18
|
int fd; /* file descriptor */
|
data/lib/heap_dump/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heap_dump
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.28
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debugger-ruby_core_source
|
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
105
|
version: '0'
|
106
106
|
segments:
|
107
107
|
- 0
|
108
|
-
hash: -
|
108
|
+
hash: -3488312299511292318
|
109
109
|
requirements: []
|
110
110
|
rubyforge_project:
|
111
111
|
rubygems_version: 1.8.24
|