Object memory layout in Common Lisp - memory
I know that Common Lisp discourages a programmer from touching raw memory, but I would like to know whether it is possible to see how an object is stored on a byte level. Of course, a garbage collector moves objects in memory space and two subsequent calls of a function (obj-as-bytes obj) could yield different results, but let us assume that we need just a memory snapshot. How would you implement such function?
My attempt with SBCL looks as follows:
(defun obj-as-bytes (obj)
(let* ((addr (sb-kernel:get-lisp-obj-address obj)) ;; get obj address in memory
(ptr (sb-sys:int-sap addr)) ;; make pointer to this area
(size (sb-ext:primitive-object-size obj)) ;; get object size
(output))
(dotimes (idx size)
(push (sb-sys:sap-ref-64 ptr idx) output)) ;; collect raw bytes into list
(nreverse output))) ;; return bytes in the reversed order
Let's try:
(obj-as-bytes #(1)) =>
(0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 111 40 161 4 16 0 0 0 23 1 16 80 0 0 0)
(obj-as-bytes #(2) =>
(0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 95 66 161 4 16 0 0 0 23 1 16 80 0 0 0)
From this output I conclude that there is a lot of garbage, which occupies space for future memory allocations. And we see it because (sb-ext:primitive-object-size obj) seems to return a chunk of memory which is large enough to fit the object.
This code demonstrates it:
(loop for n from 0 below 64 collect
(sb-ext:primitive-object-size (make-string n :initial-element #\a))) =>
(16 32 32 32 32 48 48 48 48 64 64 64 64 80 80 80 80 96 96 96 96 112 112 112 112 128 128 128 128 144 144 144 144 160 160 160 160 176 176 176 176 192 192 192 192 208 208 208 208 224 224 224 224 240 240 240 240 256 256 256 256 272 272 272)
So, obj-as-bytes would give a correct result if sb-ext:primitive-object-size were more accurate. But I cannot find any alternative.
Do you have any suggestions how to fix this function or how to implement it differently?
As I mentioned in a comment the layout of objects in memory is very implementation-specific and the tools to explore it are necessarily also implementation-dependent.
This answer discusses the layout for 64-bit versions of SBCL and only for 64-bit versions which have 'wide fixnums'. I'm not sure in which order these two things arrived in SBCL as I haven't looked seriously at any of this since well before SBCL and CMUCL diverged.
This answer also may be wrong: I'm not an SBCL developer and I'm only adding it because no one who is has (I suspect tagging the question properly might help with this).
Information below comes from looking at the GitHub mirror, which seems to be very up to date with the canonical source but a lot faster.
Pointers, immediate objects, tags
[Information from here.] SBCL allocates on two-word boundaries. On a 64-bit system this means that the low four bits of any address are always zero. These low four bits are used as a tag (the documentation calls this the 'lowtag') to tell you what sort of thing is in the rest of the word.
A lowtag of xyz0 means that the rest of the word is a fixnum, and in particular xyz will then be the low bits of the fixnum, rather than tag bits at all. This means both that there are 63 bits available for fixnums and that fixnum addition is trivial: you don't need to mask off any bits.
A lowtag of xy01 means that the rest of the word is some other immediate object. Some of the bits to the right of the lowtag (which I think SBCL calls a 'widetag' although I am confused about this as the term seems to be used in two ways) will say what the immediate object is. Examples of immediate objects are characters and single-floats (on a 64-bit platform!).
the remaining lowtag patterns are xy11, and they all mean that things are pointers to some non-immediate object:
0011 is an instance of something;
0111 is a cons;
1011 is a function;
1111 is something else.
Conses
Because conses don't need any additional type information (a cons is a cons) the lowtag is enough: a cons is then just two words in memory, each of which in turn has lowtags &c.
Other non-immediate objects
I think (but am not sure) that all other non-immediate objects have a word which says what they are (which may also be called a 'widetag') and at least one other word (because allocation is on two-word boundaries). I suspect that the special tag for functions means that function call can just jump to the entry point of the function's code.
Looking at this
room.lisp has a nice function called hexdump which knows how to print out non-immediate objects. Based on that I wrote a little shim (below) which tries to tell you useful things. Here are some examples.
> (hexdump-thing 1)
lowtags: 0010
fixnum: 0000000000000002 = 1
1 is a fixnum and its representation is just shifted right one bit as described above. Note that the lowtags actually contain the whole value in this case!
> (hexdump-thing 85757)
lowtags: 1010
fixnum: 0000000000029DFA = 85757
... but not in this case.
> (hexdump-thing #\c)
lowtags: 1001
immediate: 0000000000006349 = #\c
> (hexdump-thing 1.0s0)
lowtags: 1001
immediate: 3F80000000000019 = 1.0
Characters and single floats are immediate: some of the bits to the left of the lowtag tells the system what they are, I think?
> (hexdump-thing '(1 . 2))
lowtags: 0111
cons: 00000010024D6E07 : 00000010024D6E00
10024D6E00: 0000000000000002 = 1
10024D6E08: 0000000000000004 = 2
> (hexdump-thing '(1 2 3))
lowtags: 0111
cons: 00000010024E4BC7 : 00000010024E4BC0
10024E4BC0: 0000000000000002 = 1
10024E4BC8: 00000010024E4BD7 = (2 3)
Conses. In the first case you can see the two fixnums sitting as immediate values in the two fields of the cons. In the second, if you decoded the lowtag of the second field it would be 0111: it's another cons.
> (hexdump-thing "")
lowtags: 1111
other: 00000010024FAE8F : 00000010024FAE80
10024FAE80: 00000000000000E5
10024FAE88: 0000000000000000 = 0
> (hexdump-thing "x")
lowtags: 1111
other: 00000010024FC22F : 00000010024FC220
10024FC220: 00000000000000E5
10024FC228: 0000000000000002 = 1
10024FC230: 0000000000000078 = 60
10024FC238: 0000000000000000 = 0
> (hexdump-thing "xyzt")
lowtags: 1111
other: 00000010024FDDAF : 00000010024FDDA0
10024FDDA0: 00000000000000E5
10024FDDA8: 0000000000000008 = 4
10024FDDB0: 0000007900000078 = 259845521468
10024FDDB8: 000000740000007A = 249108103229
Strings. These have some type information, a length field, and then characters are packed two to a word. A single-character string needs four words, the same as a four-character one. You can read the character codes out of the data.
> (hexdump-thing #())
lowtags: 1111
other: 0000001002511C3F : 0000001002511C30
1002511C30: 0000000000000089
1002511C38: 0000000000000000 = 0
> (hexdump-thing #(1))
lowtags: 1111
other: 00000010025152BF : 00000010025152B0
10025152B0: 0000000000000089
10025152B8: 0000000000000002 = 1
10025152C0: 0000000000000002 = 1
10025152C8: 0000000000000000 = 0
> (hexdump-thing #(1 2))
lowtags: 1111
other: 000000100252DC2F : 000000100252DC20
100252DC20: 0000000000000089
100252DC28: 0000000000000004 = 2
100252DC30: 0000000000000002 = 1
100252DC38: 0000000000000004 = 2
> (hexdump-thing #(1 2 3))
lowtags: 1111
other: 0000001002531C8F : 0000001002531C80
1002531C80: 0000000000000089
1002531C88: 0000000000000006 = 3
1002531C90: 0000000000000002 = 1
1002531C98: 0000000000000004 = 2
1002531CA0: 0000000000000006 = 3
1002531CA8: 0000000000000000 = 0
Same deal for simple vectors: header, length, but now each entry takes a word of course. Above all entries are fixnums and you can see them in the data.
And so it goes on.
The code that did this
This may be wrong and an earlier version of it definitely did not like small bignums (I think hexdump doesn't like them). If you want real answers either read the source or ask an SBCL person. Other implementations are available, and will be different.
(defun hexdump-thing (obj)
;; Try and hexdump an object, including immediate objects. All the
;; work is done by sb-vm:hexdump in the interesting cases.
#-(and SBCL 64-bit)
(error "not a 64-bit SBCL")
(let* ((address/thing (sb-kernel:get-lisp-obj-address obj))
(tags (ldb (byte 4 0) address/thing)))
(format t "~&lowtags: ~12T~4,'0b~%" tags)
(cond
((zerop (ldb (byte 1 0) tags))
(format t "~&fixnum:~12T~16,'0x = ~S~%" address/thing obj))
((= (ldb (byte 2 0) tags) #b01)
(format t "~&immediate:~12T~16,'0x = ~S~%" address/thing obj))
((= (ldb (byte 2 0) tags) #b11) ;must be true
(format t "~&~A:~12T~16,'0x : ~16,'0x~%"
(case (ldb (byte 2 2) tags)
(#b00 "instance")
(#b01 "cons")
(#b10 "function")
(#b11 "other"))
address/thing (dpb #b0000 (byte 4 0) address/thing))
;; this tells you at least something (and really annoyingly
;; does not pad addresses on the left)
(sb-vm:hexdump obj))
;; can't happen
(t (error "mutant"))))
(values))
Related
How come in two's complementary, 1001 and 11111001 are both -7?
When I learned two's complimentary, I was taught, that for a signed number, 0111 represents 7, so by using two's complementary, 0111 -> 1000 + 1 -> 1001, is -7 so 1001 represents -7. While I refreshed this concept on YouTube, I see a video that is saying, 0000 0111 represents 7, so by using two's complementary, 0000 0111 -> 1111 1000 + 1 -> 1111 1001, is -7, thus, 11111001 represents -7. I got confused. So by just looking at a signed binary number, how can we determine its value? I thought 11111001 should equal to -121, since the first number MSB is 1, so it is negative, and 1111001 is -121 in decimal, so shouldn't 11111001 be -121? What did I do wrong? Thanks guys!
The only difference between the two examples is the number of bits you are using for each number. 1001 is -7 with 4 bits and 11111001 is -7 with 8 bits. If you add up the negative and the positive of the same absolute number the result will be zero. Both are -7 + 7 = 0 1001 + 0111 = 1|0000 11111001 + 00000111 = 1|00000000
Get a list of function results until result > x
I basically want the same thing as this OP: Is there a J idiom for adding to a list until a certain condition is met? But I cant get the answers to work with OP's function or my own. I will rephrase the question and write about the answers at the bottom. I am trying to create a function that will return a list of fibonacci numbers less than 2.000.000. (without writing "while" inside the function). Here is what i have tried: First, i picked a way to culculate fibonacci numbers from this site: https://code.jsoftware.com/wiki/Essays/Fibonacci_Sequence fib =: (i. +/ .! i.#-)"0 echo fib i.10 0 1 1 2 3 5 8 13 21 34 Then I made an arbitrary list I knew was larger than what I needed. : fiblist =: (fib i.40) NB. THIS IS A BAD SOLUTION! Finally, I removed the numbers that were greater than what I needed: result =: (fiblist < 2e6) # fiblist echo result 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1.34627e6 This gets the right result, but is there a way to avoid using some arbitrary number like 40 in "fib i.40" ? I would like to write a function, such that "func 2e6" returns the list of fibonacci numbers below 2.000.000. (without writing "while" inside the function). echo func 2e6 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1.34627e6 here are the answers from the other question: first answer: 2 *^:(100&>#:])^:_"0 (1 3 5 7 9 11) 128 192 160 112 144 176 second answer: +:^:(100&>)^:(<_) ] 3 3 6 12 24 48 96 192 As I understand it, I just need to replace the functions used in the answers, but i dont see how that can work. For example, if I try: echo (, [: +/ _2&{.)^:(100&>#:])^:_ i.2 I get an error.
I approached it this way. First I want to have a way of generating the nth Fibonacci number, and I used f0b from your link to the Jsoftware Essays. f0b=: (-&2 +&$: -&1) ^: (1&<) M. Once I had that I just want to put it into a verb that will check to see if the result of f0b is less than a certain amount (I used 1000) and if it was then I incremented the input and went through the process again. This is the ($:#:>:) part. $: is Self-Reference. The right 0 argument is the starting point for generating the sequence. ($:#:>: ^: (1000 > f0b)) 0 17 This tells me that the 17th Fibonacci number is the largest one less than my limit. I use that information to generate the Fibonacci numbers by applying f0b to each item in i. ($:#:>: ^: (1000 > f0b)) 0 by using rank 0 (fob"0) f0b"0 i. ($:#:>: ^: (1000 > f0b)) 0 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 In your case you wanted the ones under 2000000 f0b"0 i. ($:#:>: ^: (2000000 > f0b)) 0 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 ... and then I realized that you wanted a verb to be able to answer your original question. I went with dyadic where the left argument is the limit and the right argument generates the sequence. Same idea but I was able to make use of some hooks when I went to the tacit form. (> f0b) checks if the result of f0b is under the limit and ($: >:) increments the right argument while allowing the left argument to remain for $: 2000000 (($: >:) ^: (> f0b)) 0 32 fnum=: (($: >:) ^: (> f0b)) 2000000 fnum 0 32 f0b"0 i. 2000000 fnum 0 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 I have little doubt that others will come up with better solutions, but this is what I cobbled together tonight.
Assembly Language: Memory Bytes and Offsets
I am confused as to how memory is stored when declaring variables in assembly language. I have this block of sample code: val1 db 1,2 val2 dw 1,2 val3 db '12' From my study guide, it says that the total number of bytes required in memory to store the data declared by these three data definitions is 8 bytes (in decimal). How do I go about calculating this? It also says that the offset into the data segment of val3 is 6 bytes and the hex byte at offset 5 is 00. I'm lost as to how to calculate these bytes and offsets. Also, reading val1 into memory will produce 0102 but reading val3 into memory produces 3132. Are apostrophes represented by the 3 or where does it come from? How would val2 be read into memory?
You have two bytes, 0x01 and 0x02. That's two bytes so far. Then you have two words, 0x0001 and 0x0002. That's another four bytes, making six to date. The you have two more bytes making up the characters of the string '12', which are 0x31 and 0x32 in ASCII (a). That's another two bytes bringing the grand total to eight. In little-endian format (which is what you're looking at here based on the memory values your question states), they're stored as: offset value ------ ----- 0 0x01 1 0x02 2 0x01 3 0x00 4 0x02 5 0x00 6 0x31 7 0x32 (a) The character set you're using in this case is the ASCII one (you can follow that link for a table describing all the characters in that set). The byte values 0x30 thru 0x39 are the digits 0 thru 9, just as the bytes 0x41 thru 0x5A represent the upper-case alpha characters. The pseudo-op: db '12' is saying to insert the bytes for the characters '1' and '2'. Similarly: db 'Pax is a really cool guy',0 would give you the hex-dump representation: addr +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F +0123456789ABCDEF 0000 50 61 78 20 69 73 20 61 20 72 65 61 6C 6C 79 20 Pax is a really 0010 63 6F 6F 6C 20 67 75 79 00 cool guy.
val1 is two consecutive bytes, 1 and 2. db means "direct byte". val2 is two consecutive words, i.e. 4 bytes, again 1 and 2. in memory they will be 1, 0, 2, 0, assuming you're on a big endian machine. val3 is a two bytes string. 31 and 32 in are 49 and 50 in hexadecimal notation, they are ASCII codes for the characters "1" and "2".
Unexpected behavior of io:fread in Erlang
This is an Erlang question. I have run into some unexpected behavior by io:fread. I was wondering if someone could check whether there is something wrong with the way I use io:fread or whether there is a bug in io:fread. I have a text file which contains a "triangle of numbers"as follows: 59 73 41 52 40 09 26 53 06 34 10 51 87 86 81 61 95 66 57 25 68 90 81 80 38 92 67 73 30 28 51 76 81 18 75 44 ... There is a single space between each pair of numbers and each line ends with a carriage-return new-line pair. I use the following Erlang program to read this file into a list. -module(euler67). -author('Cayle Spandon'). -export([solve/0]). solve() -> {ok, File} = file:open("triangle.txt", [read]), Data = read_file(File), ok = file:close(File), Data. read_file(File) -> read_file(File, []). read_file(File, Data) -> case io:fread(File, "", "~d") of {ok, [N]} -> read_file(File, [N | Data]); eof -> lists:reverse(Data) end. The output of this program is: (erlide#cayle-spandons-computer.local)30> euler67:solve(). [59,73,41,52,40,9,26,53,6,3410,51,87,86,8161,95,66,57,25, 6890,81,80,38,92,67,7330,28,51,76,81|...] Note how the last number of the fourth line (34) and the first number of the fifth line (10) have been merged into a single number 3410. When I dump the text file using "od" there is nothing special about those lines; they end with cr-nl just like any other line: > od -t a triangle.txt 0000000 5 9 cr nl 7 3 sp 4 1 cr nl 5 2 sp 4 0 0000020 sp 0 9 cr nl 2 6 sp 5 3 sp 0 6 sp 3 4 0000040 cr nl 1 0 sp 5 1 sp 8 7 sp 8 6 sp 8 1 0000060 cr nl 6 1 sp 9 5 sp 6 6 sp 5 7 sp 2 5 0000100 sp 6 8 cr nl 9 0 sp 8 1 sp 8 0 sp 3 8 0000120 sp 9 2 sp 6 7 sp 7 3 cr nl 3 0 sp 2 8 0000140 sp 5 1 sp 7 6 sp 8 1 sp 1 8 sp 7 5 sp 0000160 4 4 cr nl 8 4 sp 1 4 sp 9 5 sp 8 7 sp One interesting observation is that some of the numbers for which the problem occurs happen to be on 16-byte boundary in the text file (but not all, for example 6890).
I'm going to go with it being a bug in Erlang, too, and a weird one. Changing the format string to "~2s" gives equally weird results: ["59","73","4","15","2","40","0","92","6","53","0","6","34", "10","5","1","87","8","6","81","61","9","5","66","5","7", "25","6", [...]|...] So it appears that it's counting a newline character as a regular character for the purposes of counting, but not when it comes to producing the output. Loopy as all hell. A week of Erlang programming, and I'm already delving into the source. That might be a new record for me... EDIT A bit more investigation has confirmed for me that this is a bug. Calling one of the internal methods that's used in fread: > io_lib_fread:fread([], "12 13\n14 15 16\n17 18 19 20\n", "~d"). {done,{ok,"\f"}," 1314 15 16\n17 18 19 20\n"} Basically, if there's multiple values to be read, then a newline, the first newline gets eaten in the "still to be read" part of the string. Other testing suggests that if you prepend a space it's OK, and if you lead the string with a newline it asks for more. I'm going to get to the bottom of this, gosh-darn-it... (grin) There's not that much code to go through, and not much of it deals specifically with newlines, so it shouldn't take too long to narrow it down and fix it. EDIT^2 HA HA! Got the little blighter. Here's the patch to the stdlib that you want (remember to recompile and drop the new beam file over the top of the old one): --- ../erlang/erlang-12.b.3-dfsg/lib/stdlib/src/io_lib_fread.erl +++ ./io_lib_fread.erl ## -35,9 +35,9 ## fread_collect(MoreChars, [], Rest, RestFormat, N, Inputs). fread_collect([$\r|More], Stack, Rest, RestFormat, N, Inputs) -> - fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, More); + fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, [$\r|More]); fread_collect([$\n|More], Stack, Rest, RestFormat, N, Inputs) -> - fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, More); + fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, [$\n|More]); fread_collect([C|More], Stack, Rest, RestFormat, N, Inputs) -> fread_collect(More, [C|Stack], Rest, RestFormat, N, Inputs); fread_collect([], Stack, Rest, RestFormat, N, Inputs) -> ## -55,8 +55,8 ## eof -> fread(RestFormat,eof,N,Inputs,eof); _ -> - %% Don't forget to count the newline. - {more,{More,RestFormat,N+1,Inputs}} + %% Don't forget to strip and count the newline. + {more,{tl(More),RestFormat,N+1,Inputs}} end; Other -> %An error has occurred {done,Other,More} Now to submit my patch to erlang-patches, and reap the resulting fame and glory...
Besides the fact that it seems to be a bug in one of the erlang libs I think you could (very) easily circumvent the problem. Given the fact your file is line-oriented I think best practice is that you process it line-by-line as well. Consider the following construction. It works nicely on an unpatched erlang and because it uses lazy evaluation it can handle files of arbitrary length without having to read all of it into memory first. The module contains an example of a function to apply to each line - turning a line of text-representations of integers into a list of integers. -module(liner). -author("Harro Verkouter"). -export([liner/2, integerize/0, lazyfile/1]). % Applies a function to all lines of the file % before reducing (foldl). liner(File, Fun) -> lists:foldl(fun(X, Acc) -> Acc++Fun(X) end, [], lazyfile(File)). % Reads the lines of a file in a lazy fashion lazyfile(File) -> {ok, Fd} = file:open(File, [read]), lazylines(Fd). % Actually, this one does the lazy read ;) lazylines(Fd) -> case io:get_line(Fd, "") of eof -> file:close(Fd), []; {error, Reason} -> file:close(Fd), exit(Reason); L -> [L|lazylines(Fd)] end. % Take a line of space separated integers (string) and transform % them into a list of integers integerize() -> fun(X) -> lists:map(fun(Y) -> list_to_integer(Y) end, string:tokens(X, " \n")) end. Example usage: Eshell V5.6.5 (abort with ^G) 1> c(liner). {ok,liner} 2> liner:liner("triangle.txt", liner:integerize()). [59,73,41,52,40,9,26,53,6,34,10,51,87,86,81,61,95,66,57,25, 68,90,81,80,38,92,67,73,30|...] And as a bonus, you can easily fold over the lines of any (lineoriented) file w/o running out of memory :) 6> lists:foldl( fun(X, Acc) -> 6> io:format("~.2w: ~s", [Acc,X]), Acc+1 6> end, 6> 1, 6> liner:lazyfile("triangle.txt")). 1: 59 2: 73 41 3: 52 40 09 4: 26 53 06 34 5: 10 51 87 86 81 6: 61 95 66 57 25 68 7: 90 81 80 38 92 67 73 8: 30 28 51 76 81 18 75 44 Cheers, h.
I noticed that there are multiple instances where two numbers are merged, and it appears to be at the line boundaries on every line starting at the fourth line and beyond. I found that if you add a whitespace character to the beginning of every line starting at the fifth, that is: 59 73 41 52 40 09 26 53 06 34 10 51 87 86 81 61 95 66 57 25 68 90 81 80 38 92 67 73 30 28 51 76 81 18 75 44 ... The numbers get parsed properly: 39> euler67:solve(). [59,73,41,52,40,9,26,53,6,34,10,51,87,86,81,61,95,66,57,25, 68,90,81,80,38,92,67,73,30|...] It also works if you add the whitespace to the beginning of the first four lines, as well. It's more of a workaround than an actual solution, but it works. I'd like to figure out how to set up the format string for io:fread such that we wouldn't have to do this. UPDATE Here's a workaround that won't force you to change the file. This assumes that all digits are two characters (< 100): read_file(File, Data) -> case io:fread(File, "", "~d") of {ok, [N] } -> if N > 100 -> First = N div 100, Second = N - (First * 100), read_file(File, [First , Second | Data]); true -> read_file(File, [N | Data]) end; eof -> lists:reverse(Data) end. Basically, the code catches any of the numbers which are the concatenation of two across a newline and splits them into two. Again, it's a kludge that implies a possible bug in io:fread, but that should do it. UPDATE AGAIN The above will only work for two-digit inputs, but since the example packs all digits (even those < 10) into a two-digit format, that will work for this example.
How to interpret the memory usage figures?
Can someone explain this in a practical way? Sample represents usage for one, low-traffic Rails site using Nginx and 3 Mongrel clusters. I ask because I am aiming to learn about page caching, wondering if these figures have significant meaning to that process. Thank you. Great site! me#vps:~$ free -m total used free shared buffers cached Mem: 512 506 6 0 15 103 -/+ buffers/cache: 387 124 Swap: 1023 113 910
Physical memory is all used up. Why? Because it's there, the system should be using it. You'll note also that the system is using 113M of swap space. Bad? Good? It depends. See also that there's 103M of cached disk; this means that the system has decided that it's better to cache 103M of disk and swap out these 113M; maybe you have some processes using memory that are not being used and thus are paged out to disk. As the other poster said, you should be using other tools to see what's happening: Your perception: is the site running appropiately when you use it? Benchmarking: what response times are your clients seeing? More fine-grained diagnostics: top: you can see live which processes are using memory and CPU vmstat: it produces this kind of output: alex#armitage:~$ vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 2 1 71184 156520 92524 316488 1 5 12 23 362 250 13 6 80 1 0 0 71184 156340 92528 316508 0 0 0 1 291 608 10 1 89 0 0 0 71184 156364 92528 316508 0 0 0 0 308 674 9 2 89 0 0 0 71184 156364 92532 316504 0 0 0 72 295 723 9 0 91 0 1 0 71184 150892 92532 316508 0 0 0 0 370 722 38 0 62 0 0 0 71184 163060 92532 316508 0 0 0 0 303 611 17 2 81 0 which will show you whether swap is hurting you (high numbers on si, so) and a more easier to see performance-over-time statistic.
by my reading of this, you have used almost all your memory, have 6 M free, and are going into about 10% of your swap. A more useful tools is to use top or perhaps ps to see how much each of your individual mongrels are using in RAM. Because you're going into swap, you're probably getting more slowdowns. you might find having only 2 mongrels rather than 3 might actually respond faster because it likely wouldn't go into swap memory. Page caching will for sure help a tonne on response time, so if your pages are cachable (eg, they don't have content that is unique to the individual user) I would say for sure check it out