Reading Java Hello World...
‣ Textbook import java.io.*; public class HelloWorld { • New to C, Understanding Pointers, The malloc and free Functions, Why Dynamic Memory Allocation public static void main (String[] args) { System.out.println("Hello world"); • 2ed: "New to C" sidebar of 3.4, 3.10, 9.9.1-9.9.2 } • 1ed: "New to C" sidebar of 3.4, 3.11,10.9.1-10.9.2 CPSC 213 } C vs. Java C Hello World... Introduction to Computer Systems #include
1 2 3 4 Java Syntax... vs. C Syntax New in C: Pointers C and Java Arrays and Pointers
‣ source files ‣ source files ‣ pointers: addresses in memory 0x00000000 ‣ In both languages 0x00000001 • .java is source file • .c is source file • locations are first-class citizens in C • an array is a list of items of the same type 0x00000002 • .h is header file • can go back and forth between location and value! • array elements are named by non-negative integers start with 0 0x00000003 ‣ including packages in source ‣ including headers in source ‣ pointer declaration:
5 6 7 8
Example Example Pointer Arithmetic in C Question (from S3-C-pointer-math.c)
‣ The following two C programs are identical ‣ The following two C programs are identical ‣ Its purpose int *c; • an alternative way to access dynamic arrays to the a[i] int *a; int *a; int *a; int *a; void foo () { a[4] = 5; *(a+4) = 5; a[4] = 5; *(a+4) = 5; ‣ Adding or subtracting an integer index to a pointer // ... c = (int *) malloc (10*sizeof(int)); • results in a new pointer of the same type // ... ‣ For array access, the compiler would generate this code ‣ For array access, the compiler would generate this code • value of the pointer is offset by index times size of pointer’s referent c = &c[3]; *c = *&c[3]; • for example // ... r[0] ← a ld $a, r0 r[0] ← a ld $a, r0 - adding 3 to an int* yields a pointer value 12 larger than the original } r[1] ← 4 ld $4, r1 r[1] ← 4 ld $4, r1 r[2] ← 5 ld $5, r2 r[2] ← 5 ld $5, r2 ‣ Subtracting two pointers of the same type m[r[0]+4*r[1]] ← r[2] st r2, (r0,r1,4) m[r[0]+4*r[1]] ← r[2] st r2, (r0,r1,4) • results in an integer ‣ What is the equivalent Java statement to • gives number of referent-type elements between the two pointers • multiplying the index 4 by 4 (size of integer) to compute the array offset • multiplying the index 4 by 4 (size of integer) to compute the array offset • [A] c[0] = c[3]; • for example • [B] c[3] = c[6]; ‣ So, what does this tell you about pointer arithmetic in C? ‣ So, what does this tell you about pointer arithmetic in C? - (& a[7]) - (& a[2])) == 5 == (a+7) - (a+2) • [C] there is no typesafe equivalent ‣ other operators • [D] not valid, because you can’t take the address of a static in Java Adding X to a pointer of type Y*, adds X * sizeof(Y) • & X the address of X to the pointer’s memory-address value. • * X the value X points to
9 9 10 11 Looking more closely Looking more closely ‣ And in assembly language Example: Endianness of a Computer
r[0] ← 0x2000 # r[0] = &c c = &c[3]; r[0] ← 0x2000 # r[0] = &c c = &c[3]; r[0] ← 0x2000 # r[0] = &c r[1] ← m[r[0]] # r[1] = c *c = *&c[3]; r[1] ← m[r[0]] # r[1] = c *c = *&c[3]; r[1] ← m[r[0]] # r[1] = c r[2] ← 12 # r[2] = 3 * sizeof(int) r[2] ← 12 # r[2] = 3 * sizeof(int) r[2] ← 12 # r[2] = 3 * sizeof(int) r[2] ← r[2]+r[1] # r[2] = c + 3 #include
12 12 13 14 Dynamic Allocation in C and Java Considering Explicit Delete ‣ Let's extend the example to see • what might happen in bar() ‣ Programs can allocate memory dynamically ‣ Let's look at this example • and why a subsequent call to bat() would expose a serious bug
• allocation reserves a range of memory for a purpose struct MBuf * receive () { struct MBuf * receive () { struct MBuf* mBuf = (struct MBuf*) malloc (sizeof (struct MBuf)); struct MBuf* mBuf = (struct MBuf*) malloc (sizeof (struct MBuf)); • in Java, instances of classes are allocated by the new statement ...... return mBuf; • in C, byte ranges are allocated by call to malloc function return mBuf; } } ‣ Wise management of memory requires deallocation void foo () { void foo () { • memory is a scare resource struct MBuf* mb = receive (); struct MBuf* mb = receive (); Dynamic Allocation bar (mb); bar (mb); • deallocation frees previously allocated memory for later re-use free (mb); free (mb); } } • Java and C take different approaches to deallocation void MBuf* aMB; ‣ How is memory deallocated in Java? • is it safe to free mb where it is freed? • what bad thing can happen? void bar (MBuf* mb) { aMB = mb; } ‣ Deallocation in C void bat () { This statement writes to • programs must explicitly deallocate memory by calling the free function aMB->x = 0; unallocated (or re-allocated) memory. } • free frees the memory immediately, with no check to see if its still in use
15 16 17 18 Dangling Pointers Avoiding Dangling Pointers in C Avoiding dynamic allocation Reference Counting
‣ A dangling pointer is ‣ Understand the problem ‣ If procedure returns value of dynamically allocated object ‣ Use reference counting to track object use • a pointer to an object that has been freed • when allocation and free appear in different places in your code • allocate that object in caller and pass pointer to it to callee • any procedure that stores a reference increments the count • could point to unallocated memory or to another object • for example, when a procedure returns a pointer to something it allocates • good if caller can allocate on stack or can do both malloc / free itself • any procedure that discards a reference decrements the count ‣ Why they are a problem ‣ Avoid the problem cases, if possible • the object is freed when count goes to zero struct MBuf * receive () { • program thinks its writing to object of type X, but isn’t • restrict dynamic allocation/free to single procedure, if possible struct MBuf* mBuf = (struct MBuf*) malloc (sizeof (struct MBuf)); struct MBuf* malloc_Mbuf () { ... • it may be writing to an object of type Y, consider this sequence of events struct MBuf* mb = (struct MBuf* mb) malloc (sizeof (struct MBuf)); • don’t write procedures that return pointers, if possible return mBuf; mb->ref_count = 1; } • use local variables instead, where possible return mb; (1) Before free: (2) After free: void foo () { } - since local variables are automatically allocated on call and freed on return through stack aMB: 0x2000 aMB: 0x2000 struct MBuf* mb = receive (); dangling ‣ Engineer for memory management, if necessary bar (mb); void keep_reference (struct MBuf* mb) { pointer free (mb); void receive (struct MBuf* mBuf) { mb->ref_count ++; 0x2000: a struct mbuf 0x2000: free memory } ... } • define rules for which procedure is responsible for deallocation, if possible } • implement explicit reference counting if multiple potential deallocators void free_reference (struct MBuf* mb) { (3) After another malloc: void foo () { mb->ref_count --; struct MBuf mb; if (mb->ref_count==0) • define rules for which pointers can be stored in data structures receive (&mb); aMB: 0x2000 free (mb); dangling pointer that is • use coding conventions and documentation to ensure rules are followed bar (mb); really dangerous } } 0x2000: another thing
19 20 21 22 ‣ The example code then uses reference counting like this Garbage Collection Discussion Memory Management in Java
struct MBuf * receive () { struct MBuf* mBuf = malloc_Mbuf (); ‣ In Java objects are deallocated implicitly ‣ What are the advantages of C’s explicit delete ‣ Memory leak ... • occurs when the garbage collector fails to reclaim unneeded objects return mBuf; • the program never says free } • the runtime system tracks every object reference • memory is a scarce resource and wasting it can be a serous bug • its huge problem for long-running programs where the garbage accumulates void foo () { • when an object is unreachable then it can be deallocated struct MBuf* mb = receive (); • a garbage collector runs periodically to deallocate unreachable objects ‣ How is it possible to create a memory leak in Java? bar (mb); free_reference (mb); ‣ Advantage compared to explicit delete • Java can only reclaim an object if it is unreachable } • but, unreachability is only an approximation of whether an object is needed • no dangling pointers ‣ What are the advantages of Java’s garbage collection void MBuf* aMB = 0; • an unneeded object in a hash table, for example, is never reclaimed MBuf receive () { ‣ The solution requires engineering void bar (MBuf* mb) { MBuf mBuf = new MBuf (); if (aMB != 0) ... • just as in C, you must plan for memory deallocation explicitly free_reference (aMB); return mBuf; • unlike C, however, if you make a mistake, you can not create a dangling pointer aMB = mb; } keep_reference (aMB); • in Java you remove the references, Java reclaims the objects } void foo () { ‣ Further reading MBuf mb = receive (); ‣ Is it okay to ignore deallocation in Java programs? bar (mb); • http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html }
23 24 25 26