在这种情况下,我将指针从Go传递到C函数,C函数修改该指针值(填充数组),然后在Go代码上再次使用相同的指针,确保调用{{1 }}完成后将其释放。
我有时获得关于该指针的零引用,我很难理解原因。
在这里,Go中的对象是 cpuTimesC ,在C中是 cputicks 。
我也尝试过使函数返回指针,结果相同。最奇怪的是,如果我在函数的末尾添加一个printf语句,则需要花费更长的时间才能最终得到nil错误。
C.free
错误是:
package collector
/*
#cgo LDflaGS: -lperfstat
#include <stdlib.h>
#include <stdio.h>
#include <libperfstat.h>
#include <string.h>
#include <time.h>
u_longlong_t **ref;
int getcPUTicks(uint64_t **cputicks,size_t *cpu_ticks_len) {
int i,ncpus,cputotal;
perfstat_id_t firstcpu;
perfstat_cpu_t *statp;
cputotal = perfstat_cpu(NULL,NULL,sizeof(perfstat_cpu_t),0);
if (cputotal <= 0){
return -1;
}
statp = calloc(cputotal,sizeof(perfstat_cpu_t));
if(statp==NULL){
return -1;
}
ncpus = perfstat_cpu(&firstcpu,statp,cputotal);
*cpu_ticks_len = ncpus*4;
*cputicks = (uint64_t *) malloc(sizeof(uint64_t)*(*cpu_ticks_len));
for (i = 0; i < ncpus; i++) {
int offset = 4 * i;
(*cputicks)[offset] = statp[i].user;
(*cputicks)[offset+1] = statp[i].sys;
(*cputicks)[offset+2] = statp[i].wait;
(*cputicks)[offset+3] = statp[i].idle;
}
return 0;
}
*/
import "C"
import (
"errors"
"unsafe"
"fmt"
"github.com/prometheus/client_golang/prometheus"
)
const ClocksPerSec = float64(C.CLK_TCK)
const maxCPUTimesLen = 1024 * 4
type statCollector struct {
cpu *prometheus.Desc
}
func init() {
registerCollector("cpu",true,NewCPUCollector)
}
func NewCPUCollector() (Collector,error) {
return &statCollector{
cpu: nodeCPUSecondsDesc,},nil
}
func (c *statCollector) Update(ch chan<- prometheus.Metric) error {
var fieldsCount = 4
cpuFields := []string{"user","sys","wait","idle"}
var (
cpuTimesC *C.uint64_t
cpuTimesLength C.size_t
)
if C.getcPUTicks(&cpuTimesC,&cpuTimesLength) == -1 {
return errors.New("could not retrieve CPU times")
}
defer C.free(unsafe.Pointer(cpuTimesC))
cput := (*[maxCPUTimesLen]C.u_longlong_t)(unsafe.Pointer(cpuTimesC))[:cpuTimesLength:cpuTimesLength]
cpuTicks := make([]float64,cpuTimesLength)
for i,value := range cput {
cpuTicks[i] = float64(value) / ClocksPerSec
}
for i,value := range cpuTicks {
cpux := fmt.Sprintf("CPU %d",i/fieldsCount)
ch <- prometheus.MustNewConstMetric(c.cpu,prometheus.CounterValue,value,cpux,cpuFields[i%fieldsCount])
}
return nil
}
我知道它会在这里发生,因为出于某种原因 cpuTimesC 为零:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x33 addr=0x0 pc=0x1003fcec0]
goroutine 940 [running]:
github.com/dlopes7/aix-prometheus-exporter/collector.(*statCollector).Update(0xa000100000d21b8,0xa0001000028c480,0x0,0x0)
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/cpu_aix.go:81 +0xf0
github.com/dlopes7/aix-prometheus-exporter/collector.execute(0x10043e7e7,0x3,0x1101120e0,0xa000100000d21b8,0xa0001000028c480)
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/collector.go:95 +0x6c
github.com/dlopes7/aix-prometheus-exporter/collector.AIXCollector.Collect.func1(0xa0001000028c480,0xa000100000cd440,0x10043e7e7,0xa000100000d21b8)
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/collector.go:115 +0x4c
created by github.com/dlopes7/aix-prometheus-exporter/collector.AIXCollector.Collect
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/collector.go:114 +0xf8
为什么有时该对象为零,如何使它保留在内存中,直到我调用那个cput := (*[maxCPUTimesLen]C.u_longlong_t)(unsafe.Pointer(cpuTimesC))[:cpuTimesLength:cpuTimesLength]
为止?
如果有任何区别,此标记位于C.free
的{{1}} AIX
上。