2016-04-07 25 views
2

Git'i kullanarak örnek bir paylaşılan nesne kitaplığı oluşturmaya çalışıyorum. Kod derlenmiş (go build -o libsample.so -buildmode=c-shared . komutunu kullanarak), paylaşılan bir nesne kitaplığı başarıyla oluşturulmuştur - ancak JNA (Java'dan) veya klişelerden (python'dan) dışa aktarılan yönteme erişirken panik alıyorum. Ben git yazdı kodudur:bellekte panik var

// package name: libsample.so 
package main 

import "C" 
import "fmt" 

//export Hello 
func Hello(s string) { 
    fmt.Println("Hello " + s + "!") 
} 

func main() { 
} 

Java dan bu yöntemi Hello erişirken:

import com.sun.jna.*; 

public class sample { 

    public interface GoSO extends Library { 
     GoSO INSTANCE = (GoSO) Native.loadLibrary("sample" ,GoSO.class); 
     void Hello(String s); 
    } 
    public static void main(String[] args) { 
     GoSO.INSTANCE.Hello("World"); 
    } 
} 

veya Python:

#!/usr/bin/python 
import ctypes 
lib = ctypes.CDLL("./libsample.so") 
lib.Hello("World") 

aşağıdaki hatayı alıyorum:

runtime: out of memory: cannot allocate 140042998120448-byte block (1048576 in use) 
fatal error: out of memory 

runtime stack: 
runtime.throw(0x7f5e434bfe50, 0xd) 
    /usr/local/go/src/runtime/panic.go:530 +0x92 
runtime.largeAlloc(0x7f5e4d27dc8d, 0xc800000003, 0xc82003cf08) 
    /usr/local/go/src/runtime/malloc.go:768 +0xdf 
runtime.mallocgc.func3() 
    /usr/local/go/src/runtime/malloc.go:664 +0x35 
runtime.systemstack(0x7f5e4e4d3ab8) 
    /usr/local/go/src/runtime/asm_amd64.s:291 +0x72 
runtime.mstart() 
    /usr/local/go/src/runtime/proc.go:1048 

goroutine 17 [running, locked to thread]: 
runtime.systemstack_switch() 
    /usr/local/go/src/runtime/asm_amd64.s:245 fp=0xc82003cb50 sp=0xc82003cb48 
runtime.mallocgc(0x7f5e4d27dc8d, 0x0, 0x3, 0x0) 
    /usr/local/go/src/runtime/malloc.go:665 +0x9fe fp=0xc82003cc28 sp=0xc82003cb50 
runtime.rawstring(0x7f5e4d27dc8d, 0x0, 0x0, 0x0, 0x0, 0x0) 
    /usr/local/go/src/runtime/string.go:284 +0x72 fp=0xc82003cc70 sp=0xc82003cc28 
runtime.rawstringtmp(0x0, 0x7f5e4d27dc8d, 0x0, 0x0, 0x0, 0x0, 0x0) 
    /usr/local/go/src/runtime/string.go:111 +0xb9 fp=0xc82003cca8 sp=0xc82003cc70 
runtime.concatstrings(0x0, 0xc82003ce38, 0x3, 0x3, 0x0, 0x0) 
    /usr/local/go/src/runtime/string.go:49 +0x1bf fp=0xc82003cde0 sp=0xc82003cca8 
runtime.concatstring3(0x0, 0x7f5e434ba9d0, 0x6, 0x7f5e48155490, 0x7f5e4d27dc86, 0x7f5e434ba560, 0x1, 0x0, 0x0) 
    /usr/local/go/src/runtime/string.go:63 +0x6c fp=0xc82003ce30 sp=0xc82003cde0 
main.Hello(0x7f5e48155490, 0x7f5e4d27dc86) 
    /home/vagrant/go/src/github.com/venkatramachandran/lib-sample/sample.go:9 +0x72 fp=0xc82003cec8 sp=0xc82003ce30 
main._cgoexpwrap_9f7405a93e67_Hello(0x7f5e48155490, 0x7f5e4d27dc86) 
    github.com/venkatramachandran/lib-sample/_obj/_cgo_gotypes.go:48 +0x2d fp=0xc82003cee0 sp=0xc82003cec8 
runtime.call32(0x0, 0x7f5e4e4d3ae8, 0x7f5e4e4d3b70, 0x10) 
    /usr/local/go/src/runtime/asm_amd64.s:472 +0x40 fp=0xc82003cf08 sp=0xc82003cee0 
runtime.cgocallbackg1() 
    /usr/local/go/src/runtime/cgocall.go:267 +0x110 fp=0xc82003cf40 sp=0xc82003cf08 
runtime.cgocallbackg() 
    /usr/local/go/src/runtime/cgocall.go:180 +0xd9 fp=0xc82003cfa0 sp=0xc82003cf40 
runtime.cgocallback_gofunc(0x0, 0x0, 0x0) 
    /usr/local/go/src/runtime/asm_amd64.s:716 +0x5d fp=0xc82003cfb0 sp=0xc82003cfa0 
runtime.goexit() 
    /usr/local/go/src/runtime/asm_amd64.s:1998 +0x1 fp=0xc82003cfb8 sp=0xc82003cfb0 

goroutine 18 [syscall, locked to thread]: 
runtime.goexit() 
    /usr/local/go/src/runtime/asm_amd64.s:1998 +0x1 
Aborted (core dumped) 

Neler yanlış gidiyor? Bir parametre olarak bir int veya float ile yöntem oluşturursam, bu hata oluşmaz.

cevap

4

Sebep: Bunun arkasındaki nedeni, go fonksiyonu Hello bir golang String, ancak piton beklediğini ve Java C style dize geçirilmesi olmasıdır.

Çözüm: buildmode=c-shared kullanarak golang kütüphane derledik yana . Python ctypes paket ve java JNI onu sade bir c yöntemi olarak görür. Ve gerçekten de sadece NULL tarafından sonlandırılan bir dizi karakter olan bir c stili dizesi geçer.

Ancak, kodunuzda, Hello işlevi, tipik c stili dizgeden farklı biçime sahip bir golang dizesini bekler. Bu yüzden bu hata. *C.char olarak s bildirerek çözülebilir. aşağıdaki gibi

Düzeltilmiş programdır:

// package name: libsample.so 
package main 

import "C" 
import "fmt" 

//export Hello 
func Hello(s *C.char) { 
    fmt.Println("Hello " + C.GoString(s) + "!") 
} 

func main() { 
}